leetcode-2.两数之和
leetcode-2.两数之和
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){struct ListNode* head = NULL, * tail = NULL;int carry = 0;while(l1 || l2){int a = l1 ? l1->val : 0;int b = l2 ? l2->val : 0;if(!head){head = tail = malloc(sizeof(struct ListNode));tail->val = (a + b + carry) % 10;tail->next = NULL;}else{tail->next = malloc(sizeof(struct ListNode));tail->next->val = (a + b + carry) % 10;tail = tail-> next;tail->next = NULL;}carry = (a + b + carry) / 10;if(l1){l1 = l1->next;}if(l2){l2 = l2->next;}}if(carry > 0){tail->next = malloc(sizeof(struct ListNode));tail->next->val = carry;tail = tail->next;tail->next = NULL;}return head;
}
leetcode-19.删除链表的倒数第N个结点
leetcode-19.删除链表的倒数第N个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){struct ListNode* headNode = (struct ListNode*)malloc(sizeof(struct ListNode));headNode->val = 0;headNode->next = head;struct ListNode* fast = head;struct ListNode* slow = headNode;int len = 0;while(len < n){len++;fast = fast->next;}while(fast != NULL){slow = slow->next;fast = fast->next;}slow->next = slow->next->next;struct ListNode* ret = headNode->next;free(headNode);return ret;
}
时间复杂度:O(L),其中L是链表的长度。
空间复杂度:O(1)。
leetcode-21.合并两个有序链表
leetcode-21.合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
方法一:带头结点
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){if(list1 == NULL) return list2;if(list2 == NULL) return list1;struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* tail = head;while(list1 != NULL && list2 != NULL){if(list1->val < list2->val){tail->next = list1;list1 = list1->next;}else{tail->next = list2;list2 = list2->next;}tail = tail->next;}if(list1 != NULL) tail->next = list1;else tail->next = list2;struct ListNode* first = head->next;free(head);return first;
}
方法二:不带头结点
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){if(list1 == NULL) return list2;if(list2 == NULL) return list1;struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));if(list1->val < list2->val){head = list1;list1 = list1->next;}else{head = list2;list2 = list2->next;}struct ListNode* tail = head;while(list1 != NULL && list2 != NULL){if(list1->val < list2->val){tail->next = list1;list1 = list1->next;}else{tail->next = list2;list2 = list2->next;}tail = tail->next;}if(list1 != NULL) tail->next = list1;else tail->next = list2;return head;
}
时间复杂度:O(n + m),其中 n 和 m 分别为两个链表的长度。因为每次循环迭代中,list1 和 list2 只有一个元素会被放进合并链表中, 因此 while 循环的次数不会超过两个链表的长度之和。所有其他操作的时间复杂度都是常数级别的,因此总的时间复杂度为 O(n + m)。
空间复杂度:O(1)。我们只需要常数的空间存放若干变量。
leetcode-24.两两交换链表中的节点
leetcode-24.两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
struct ListNode* swapPairs(struct ListNode* head){struct ListNode* swapList = (struct ListNode*)malloc(sizeof(struct ListNode));swapList->next = head;struct ListNode* temp = swapList;while(temp->next != NULL && temp->next->next != NULL){struct ListNode* node1 = temp->next;struct ListNode* node2 = temp->next->next;temp->next = node2;node1->next = node2->next;node2->next = node1;temp = node1;}return swapList->next;
}
时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。
空间复杂度:O(1)。
leetcode-61.循环链表
leetcode-61.循环链表
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
struct ListNode* rotateRight(struct ListNode* head, int k){if(head == NULL)return NULL;struct ListNode* p = head;int n = 1; // 用于计算链表长度while(p->next != NULL){p = p->next;n++;}p->next = head; // head 变为循环链表int m = n - k % n; // 计算移位后头节点的前一个节点while(m > 0){p = p-> next;m--;}head = p->next; // 将移位后的头节点赋给 headp->next = NULL; // 断开循环链表return head;
}
时间复杂度:O(n)。
空间复杂度:O(1)。
leetcode-82.删除排序链表中的重复元素 II
leetcode-82.删除排序链表中的重复元素 II
给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* deleteDuplicates(struct ListNode* head){if(!head){return head;}struct ListNode* h = malloc(sizeof(struct ListNode));h->next = head;struct ListNode* cur = h;while(cur->next && cur->next->next){if(cur->next->val == cur->next->next->val){int x = cur->next->val;while(cur->next && cur->next->val == x){cur->next = cur->next->next;}}else{cur = cur->next;}}return h->next;
}
时间复杂度:O(n),其中 n 是链表的长度。
空间复杂度:O(1)。
leetcode-83.删除排序链表中的重复元素
leetcode-83.删除排序链表中的重复元素
给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* deleteDuplicates(struct ListNode* head){if(!head){return head;}struct ListNode* cur = malloc(sizeof(struct ListNode));cur = head;while(cur->next){if(cur->val == cur->next->val){cur->next = cur->next->next;}else{cur = cur->next;}}return head;
}
时间复杂度:O(n),其中 n 是链表的长度。
空间复杂度:O(1)。
leetcode-86.分隔链表
leetcode-86.分隔链表
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* partition(struct ListNode* head, int x){struct ListNode* small = malloc(sizeof(struct ListNode));struct ListNode* smallHead = small;struct ListNode* large = malloc(sizeof(struct ListNode));struct ListNode* largeHead = large;while(head != NULL){if(head->val < x){small->next = head;small = small->next;}else{large->next = head;large = large->next;}head = head->next;}large->next = NULL;small->next = largeHead->next;return smallHead->next;
}
时间复杂度:O(n),其中 n 是原链表的长度。我们对该链表进行了一次遍历。
空间复杂度:O(1)。
leetcode-92.反转链表 II
leetcode-92.反转链表 II
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
struct ListNode* reverseBetween(struct ListNode* head, int left, int right){struct ListNode* node = malloc(sizeof(struct ListNode));node->next = head;struct ListNode* pre = malloc(sizeof(struct ListNode));pre = node;int t = 1;while(t < left){pre = pre->next;t++;}struct ListNode* cur = pre->next;struct ListNode* l;while(t < right){l = cur->next;cur->next = cur->next->next;l->next = pre->next;pre->next = l;t++;}return node->next;
}
时间复杂度:O(n),其中 n 是链表总节点数。最多只遍历了链表一次,就完成了反转。
空间复杂度:O(1)。只使用到常数个变量。
leetcode-141.环形链表
leetcode-141.环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
bool hasCycle(struct ListNode *head) {if(head == NULL || head->next == NULL)return false;struct ListNode* slow = head;struct ListNode* fast = head->next;while(slow != fast){if(fast == NULL || fast->next == NULL)return false;slow = slow->next;fast = fast->next->next;}return true;
}
时间复杂度:O(N),其中 N 是链表中的节点数。
- 当链表中不存在环时,快指针将先于慢指针到达链表尾部,链表中每个节点至多被访问两次。
- 当链表中存在环时,每一轮移动后,快慢指针的距离将减小一。而初始距离为环的长度,因此至多移动 N 轮。
空间复杂度:O(1)。我们只使用了两个指针的额外空间。
leetcode-142.环形链表 II
leetcode-142.环形链表 II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* slow = head;struct ListNode* fast = head;while(fast != NULL){slow = slow->next;if(fast->next == NULL)return NULL;fast = fast->next->next;if(slow == fast){struct ListNode* ptr = head;while(ptr != slow){ptr = ptr->next;slow = slow->next;}return ptr;}}return NULL;
}
时间复杂度:O(N),其中 N 为链表中节点的数目。在最初判断快慢指针是否相遇时,slow 指针走过的距离不会超过链表的总长度;随后寻找入环点时,走过的距离也不会超过链表的总长度。因此,总的执行时间为 O(N)+O(N)=O(N)。
空间复杂度:O(1)。我们只使用了 slow,fast,ptr 三个指针。
leetcode-143.重排链表
leetcode-143.重排链表
// 找中间节点
struct ListNode* middleNode(struct ListNode* head)
{struct ListNode* slow = head;struct ListNode* fast = head;while(fast->next != NULL && fast->next->next != NULL){slow = slow->next;fast = fast->next->next;}return slow;
}// 反转链表
struct ListNode* reverseList(struct ListNode* head)
{struct ListNode* prev = NULL;struct ListNode* nxt = head;while(nxt != NULL){struct ListNode* nxtTmp = nxt->next;nxt->next = prev;prev = nxt;nxt = nxtTmp;}return prev;
}// 合并链表
void mergeList(struct ListNode* l1, struct ListNode* l2)
{struct ListNode* l1_tmp;struct ListNode* l2_tmp;while(l1 != NULL && l2 != NULL){l1_tmp = l1->next;l2_tmp = l2->next;l1->next = l2;l1 = l1_tmp;l2->next = l1;l2 = l2_tmp;}
}void reorderList(struct ListNode* head){if(head == NULL)return ;struct ListNode* mid = middleNode(head);struct ListNode* left = head;struct ListNode* right = mid->next;mid->next = NULL;right = reverseList(right);mergeList(left, right);
}
时间复杂度:O(N),其中 N 是链表中的节点数。
空间复杂度:O(1)。
leetcode-147.对链表进行插入排序
leetcode-147.对链表进行插入排序
给定单个链表的头 head ,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。
插入排序 算法的步骤:
插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
重复直到所有输入数据插入完为止。
下面是插入排序算法的一个图形示例。部分排序的列表(黑色)最初只包含列表中的第一个元素。每次迭代时,从输入数据中删除一个元素(红色),并就地插入已排序的列表中。
对链表进行插入排序。
struct ListNode* insertionSortList(struct ListNode* head){if(head == NULL){return head;} struct ListNode* dummyHead = malloc(sizeof(struct ListNode));dummyHead->val = 0;dummyHead->next = head;struct ListNode* lastSorted = head;struct ListNode* curr = head->next;while(curr != NULL){if(lastSorted->val <= curr->val){lastSorted = lastSorted->next;}else{struct ListNode* prev = dummyHead;while(prev->next->val <= curr->val){prev = prev->next;}lastSorted->next = curr->next;curr->next = prev->next;prev->next = curr;}curr = lastSorted->next;}return dummyHead->next;
}
时间复杂度: O(n2),其中 n 是链表的长度。
空间复杂度:O(1)。
leetcode-160.相交链表
leetcode-160.相交链表
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {if(headA == NULL || headB == NULL){return NULL;}struct ListNode* la = headA;struct ListNode* lb = headB;while(la != lb){la = la == NULL ? headB : la->next;lb = lb == NULL ? headA : lb->next;}return la;
}
若相交,链表A: a+c, 链表B : b+c,a+c+b+c = b+c+a+c 。则会在公共处c起点相遇。
若不相交,a+b = b+a 。因此相遇处是NULL。
时间复杂度:O(m+n),其中 m 和 n 是分别是链表 headA 和 headB 的长度。两个指针同时遍历两个链表,每个指针遍历两个链表各一次。
空间复杂度:O(1)。
leetcode-203.移出链表元素
leetcode-203.移出链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
struct ListNode* removeElements(struct ListNode* head, int val){if(head == NULL){return NULL;}struct ListNode* node = malloc(sizeof(struct ListNode));node->next = head;struct ListNode* pre = node;while(pre->next != NULL){if(pre->next->val == val){pre->next = pre->next->next;}else{pre = pre->next; }}return node->next;
}
时间复杂度:O(n),其中 n 是链表的长度。需要遍历链表一次。
空间复杂度:O(1)。
leetcode-206.反转链表
leetcode-206.反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
struct ListNode* reverseList(struct ListNode* head){struct ListNode* node1 = NULL;struct ListNode* node2 = head;while(node2 != NULL){struct ListNode* nxt = node2->next;node2->next = node1;node1 = node2;node2 = nxt;}return node1;
}
时间复杂度:O(n),其中 n 是链表的长度。需要遍历链表一次。
空间复杂度:O(1)。
leetcode-234.回文链表
leetcode-234.回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
struct ListNode* reverseList(struct ListNode* head)
{struct ListNode* prev = NULL;struct ListNode* curr = head;while(curr != NULL){struct ListNode* nextTemp = curr->next;curr->next = prev;prev = curr;curr = nextTemp;}return prev;
}struct ListNode* endOfFirstHalf(struct ListNode* head)
{struct ListNode* fast = head;struct ListNode* slow = head;while(fast->next != NULL && fast->next->next != NULL){fast = fast->next->next;slow = slow->next;}return slow;
}bool isPalindrome(struct ListNode* head){if(head == NULL){return true;}// 找到前半部分链表的尾结点并反转后半部分链表struct ListNode* firstHalfEnd = endOfFirstHalf(head);struct ListNode* secondHalfStart = reverseList(firstHalfEnd->next);// 判断是否回文struct ListNode* p1 = head;struct ListNode* p2 = secondHalfStart;bool res = true;while(res && p2 != NULL){if(p1->val != p2->val){res = false;}p1 = p1->next;p2 = p2->next;}// 还原链表并返回结果firstHalfEnd->next = reverseList(secondHalfStart);return res;
}
时间复杂度:O(n),其中 n 指的是链表的大小。
空间复杂度:O(1)。我们只会修改原本链表中节点的指向,而在堆栈上的堆栈帧不超过 O(1)。
leetcode-237.删除链表中的节点
leetcode-237.删除链表中的节点
有一个单链表的 head,我们想删除它其中的一个节点 node。
给你一个需要删除的节点 node 。你将 无法访问 第一个节点 head。
链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。
删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:
给定节点的值不应该存在于链表中。
链表中的节点数应该减少 1。
node 前面的所有值顺序相同。
node 后面的所有值顺序相同。
void deleteNode(struct ListNode* node) {node->val = node->next->val;node->next = node->next->next;
}
时间复杂度:O(1)。
空间复杂度:O(1)。
leetcode-328.奇偶链表
leetcode-328.奇偶链表
给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。
第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。
请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。
你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。
struct ListNode* oddEvenList(struct ListNode* head){if(head == NULL){return NULL;}struct ListNode* evenhead = head->next;struct ListNode* odd = head;struct ListNode* even = evenhead;while(even != NULL && even->next != NULL){odd->next = even->next;odd = odd->next;even->next = odd->next;even = even->next;}odd->next = evenhead;return head;
}
时间复杂度:O(n),其中 n 是链表的节点数。需要遍历链表中的每个节点,并更新指针。
空间复杂度:O(1)。只需要维护有限的指针。