🤞1. 反转链表
代码实现:
方法一:非递归 + 无虚拟头结点
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* reverseList(struct ListNode *head) { if (head == NULL || head->next == NULL) { return head; } struct ListNode *p = head; struct ListNode *pc = NULL; head = NULL; while (p) { pc = p; p = p->next; pc->next = NULL; if (head == NULL) { // 从无到有 head = pc; } else { // 从少到多,头插 pc->next = head; head = pc; } } return head; }
方法二:非递归 + 虚拟头结点
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* reverseList(struct ListNode *head) { struct ListNode *h = malloc(sizeof(*h)); h->next = NULL; struct ListNode *p = head, *pc = NULL; while (p) { pc = p; p = p->next; pc->next = NULL; // 头插 pc->next = h->next; h->next = pc; } return h->next; }
方法三:递归
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* reverseList(struct ListNode *head) { if (head == NULL || head->next == NULL) { return head; } // 记录当前节点(头结点)的下一个节点,就是反转以后的尾节点 struct ListNode *tail = head->next; struct ListNode *new_head = reverseList(head->next); head->next = tail->next; tail->next = head; return new_head; }
🤞2. 反转链表 ||
代码实现:
方法一:递归——>难点
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* reverseBetween(struct ListNode *head, int left, int right) { if (left == 1 && right == 1) { return head; } if (left != 1) { head->next = reverseBetween(head->next, left - 1, right - 1); } else { struct ListNode *tail = head->next; struct ListNode *new_head = reverseBetween(head->next, left, right - 1); head->next = tail->next; tail->next = head; head = new_head; } return head; }
方法二:反转链表(递归) + 虚拟头结点
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ // 反转链表 void reverse(struct ListNode *head) { if (head == NULL || head->next == NULL) { return; } struct ListNode *tail = head->next; reverse(head->next); head->next = tail->next; tail->next = head; } struct ListNode* reverseBetween(struct ListNode *head, int left, int right) { if (left == right) { return head; } struct ListNode *h = malloc(sizeof(*h)); // 虚拟头节点 h->next = head; struct ListNode *pp = h; // 遍历指针 struct ListNode *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL; int i = 0; while (pp) { if (i == left - 1) { p1 = pp; } if (i == left) { p2 = pp; } if (i == right) { p3 = pp; } if (i == right + 1) { p4 = pp; } if (p1 && p2 && p3 && p4) { // 都找到了,跳出循环 break; } i++; pp = pp->next; } p3->next = NULL; reverse(p2); p1->next = p3; p2->next = p4; return h->next; }
方法三:非递归 + 虚拟头结点
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ // 反转链表 struct ListNode* reverseList(struct ListNode *head, struct ListNode **tail) { if (head == NULL || head->next == NULL) { return head; } struct ListNode *p = head; struct ListNode *pc = NULL; *tail = head; head = NULL; while (p) { pc = p; p = p->next; pc->next = NULL; if (head == NULL) { head = pc; } else { // 头插 pc->next = head; head = pc; } } return head; } struct ListNode* reverseBetween(struct ListNode *head, int left, int right) { if (left == right) { return head; } struct ListNode *h = malloc(sizeof(*h)); // 虚拟头节点 h->next = head; struct ListNode *pp = h; // 遍历指针 struct ListNode *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL; int i = 0; while (pp) { if (i == left - 1) { p1 = pp; } if (i == left) { p2 = pp; } if (i == right) { p3 = pp; } if (i == right + 1) { p4 = pp; } if (p1 && p2 && p3 && p4) { // 都找到了,跳出循环 break; } i++; pp = pp->next; } p3->next = NULL; p2 = reverseList(p2, &p3); p1->next = p2; p3->next = p4; return h->next; }
🤞3. 环形链表
代码实现:
快慢指针
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ bool hasCycle(struct ListNode *head) { // 快慢指针:快指针每次走两步,慢指针每次走一步,二者若重合则链表中有环,否则无环 struct ListNode *slow = head, *fast = head; while (fast && fast->next) { fast = fast->next->next; slow = slow->next; if (fast == slow) { return true; } } return false; }
🤞4. 两数相加
代码实现:
方法一:逐位相加,模拟进位
设置虚拟头结点
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* addTwoNumbers(struct ListNode *l1, struct ListNode *l2) { struct ListNode *head = (struct ListNode*)malloc(sizeof(struct ListNode)); // 虚拟头结点 struct ListNode *tail = head; int carry = 0; while (l1 || l2 || carry) { int a = l1 ? l1->val : 0; int b = l2 ? l2->val : 0; int sum = a + b + carry; carry = sum / 10; // 创建一个新结点 struct ListNode *p = (struct ListNode*)malloc(sizeof(struct ListNode)); p->val = sum % 10; p->next = NULL; // 尾插 tail->next = p; tail = p; // 指针往后走 if (l1) { l1 = l1->next; } if (l2) { l2 = l2->next; } } return head->next; }
方法二:不设置虚拟头结点
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* addTwoNumbers(struct ListNode *l1, struct ListNode *l2) { int flag = 0; // 标志进位 struct ListNode *h = NULL; // 返回头结点 struct ListNode *tail = NULL; // 指向尾结点 while (l1 || l2 || flag) { int sum = 0; if (l1) { sum += l1->val; l1 = l1->next; } if (l2) { sum += l2->val; l2 = l2->next; } sum += flag; struct ListNode *p = malloc(sizeof(*p)); p->next = NULL; p->val = sum % 10; flag = sum / 10; // 进位 if (h == NULL) { // 从无到有 h = p; tail = p; } else { // 从少到多,尾插 tail->next = p; tail = p; } } return h; }
方法三:递归
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ int c = 0; struct ListNode* addTwoNumbers(struct ListNode *l1, struct ListNode *l2) { if (l1 == NULL && l2 == NULL && c == 0) { // 边界条件 return NULL; } if (l1) { c += l1->val; l1 = l1->next; } if (l2) { c += l2->val; l2 = l2->next; } struct ListNode *p = (struct ListNode*)malloc(sizeof(struct ListNode)); p->val = c % 10; c /= 10; p->next = addTwoNumbers(l1, l2); return p; }
🤞5. 两数相加 ||
代码实现:
方法一:反转链表
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ // 反转链表 struct ListNode* reverseList(struct ListNode *head) { if (head == NULL || head->next == NULL) { return head; } struct ListNode *tail = head->next; struct ListNode *new_head = reverseList(head->next); head->next = tail->next; tail->next = head; return new_head; } // 两数相加 int c = 0; struct ListNode* func(struct ListNode *l1, struct ListNode *l2) { if (l1 == NULL && l2 == NULL && c == 0) { // 边界条件 return NULL; } l1 = l1 != NULL ? (c += l1->val, l1->next) : l1; l2 = l2 != NULL ? (c += l2->val, l2->next) : l2; struct ListNode *p = (struct ListNode*)malloc(sizeof(struct ListNode)); p->val = c % 10; c /= 10; p->next = func(l1, l2); return p; } struct ListNode* addTwoNumbers(struct ListNode *l1, struct ListNode *l2){ if (l1 == NULL || l2 == NULL) { return l1 ? l1 : l2; } // 反转l1 l1 = reverseList(l1); // 反转l2 l2 = reverseList(l2); struct ListNode *p = func(l1, l2); // 两数相加 // 反转p p = reverseList(p); return p; }
方法二:栈
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* addTwoNumbers(struct ListNode *l1, struct ListNode *l2) { int stack1[100]; int top1 = -1; int stack2[100]; int top2 = -1; // l1进栈 while (l1) { stack1[++top1] = l1->val; l1 = l1->next; } // l2进栈 while (l2) { stack2[++top2] = l2->val; l2 = l2->next; } int c = 0; struct ListNode *head = malloc(sizeof(*head)); head->next = NULL; while (top1 != -1 || top2 != -1 || c) { int a = top1 == -1 ? 0 : stack1[top1--]; int b = top2 == -1 ? 0 : stack2[top2--]; int cur = a + b + c; c = cur / 10; cur %= 10; struct ListNode *p = malloc(sizeof(*p)); p->val = cur; // 头插 p->next = head->next; head->next = p; } return head->next; }
🤞6. 删除排序链表中的重复元素
代码实现:
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* deleteDuplicates(struct ListNode *head) { if (head == NULL || head->next == NULL) { return head; } struct ListNode *p = head->next; // 遍历指针 struct ListNode *pre = head; // 遍历指针的前驱节点 struct ListNode *pc = NULL; while (p) { if (pre->val == p->val) { pc = p; pre->next = p->next; p = p->next; pc->next = NULL; free(pc); } else { pre = p; p = p->next; } } return head; }
🤞7. 删除排序链表中的重复元素 ||
代码实现:
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* deleteDuplicates(struct ListNode *head) { if (head == NULL || head->next == NULL) { return head; } struct ListNode *h = malloc(sizeof(*h)); // 创建虚拟头结点 h->next = head; struct ListNode *pre = h; struct ListNode *p = head, *p_next = head->next, *pc = NULL; while (p_next) { if (p->val != p_next->val) { pre = p; p = p->next; p_next = p_next->next; } else { while (p_next && p->val == p_next->val) { p_next = p_next->next; } pre->next = p_next; while (p != p_next) { pc = p; p = p->next; pc->next = NULL; free(pc); } if (p_next) { p_next = p_next->next; } } } return h->next; }
🤞8. 奇偶链表
代码实现:
分离节点后合并
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* oddEvenList(struct ListNode *head) { if (head == NULL) { return head; } struct ListNode *h = head->next; struct ListNode *p1 = head; struct ListNode *p2 = head->next; while (p2 != NULL && p2->next != NULL) { p1->next = p2->next; p1 = p1->next; p2->next = p1->next; p2 = p2->next; } p1->next = h; return head; }
🤞9. 两两交换链表中的节点
代码实现:
方法一:(设置虚拟头结点) 非递归
struct ListNode* swapPairs(struct ListNode *head) { if (head == NULL || head->next == NULL) { return head; } struct ListNode *h = (struct ListNode*)malloc(sizeof(struct ListNode)); h->next = head; struct ListNode *now = h; while (now->next && now->next->next) { struct ListNode *l = now->next, *r = now->next->next; now->next = r; l->next = r->next; r->next = l; now = l; } return h->next; }
方法二:(不设置虚拟头结点) 非递归
struct ListNode* swapPairs(struct ListNode *head) { // 若节点小于2个,直接返回 if (head == NULL || head->next == NULL) { return head; } struct ListNode *first = head; struct ListNode *second = head->next; // 至少交换一次,返回新头节点指向原head的第二个节点 struct ListNode *newHead = second; struct ListNode *tail = NULL; // 指向每次交换的尾,用于指向以后交换的头 while (first && second) { if (tail == NULL) { tail = first; } else { tail->next = second; tail = first; } first->next = second->next; second->next = first; first = first->next; if (first) { second = first->next; } } return newHead; }
方法三:递归
struct ListNode* swapPairs(struct ListNode *head) { if (head == NULL || head->next == NULL) { return head; } struct ListNode *first = head; struct ListNode *second = head->next; head = second; first->next = second->next; second->next = first; first->next = swapPairs(first->next); return head; }
🤞10. 删除链表的倒数第N个节点
代码实现:
方法一:双指针法
struct ListNode* removeNthFromEnd(struct ListNode *head, int n) { struct ListNode *h = (struct ListNode*)malloc(sizeof(struct ListNode)); // 虚拟头结点 h->next = head; struct ListNode *slow = h, *fast = head; while (n--) { fast = fast->next; } while (fast) { // 让慢指针移到倒数第n个结点的前一个结点 slow = slow->next; fast = fast->next; } struct ListNode *temp = slow->next; slow->next = temp->next; temp->next = NULL; free(temp); return h->next; }
方法二:常规解法
struct ListNode* removeNthFromEnd(struct ListNode *head, int n) { struct ListNode *h = malloc(sizeof(*h)); // 虚拟头结点 h->next = head; struct ListNode *p = head; // 遍历指针 int len = 0; while (p) { // 统计链表结点长度 p = p->next; len++; } int i = len - n; p = h; while (i--) { p = p->next; // 让p指向倒数第n个结点的前一个结点 } struct ListNode *pc = p->next; p->next = pc->next; pc->next = NULL; free(pc); return h->next; }
🤞11. 环形链表 ||
代码实现:
使用一个数组来存储已经访问过的节点
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode *detectCycle(struct ListNode *head) { if (head == NULL || head->next == NULL) { return NULL; } struct ListNode *slow = head; struct ListNode *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) { break; } } if (slow != fast) { return NULL; } struct ListNode *arr[10000]; int arrSize = 0; arr[arrSize++] = head; struct ListNode *p = head->next; while (p) { for (int i = 0; i < arrSize; i++) { if (arr[i] == p) { return p; } } arr[arrSize++] = p; p = p->next; } return NULL; }
🤞12. 相交链表
代码实现:
暴力法
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* getIntersectionNode(struct ListNode *headA, struct ListNode *headB) { struct ListNode *l1 = headA; while (l1) { struct ListNode *l2 = headB; while (l2) { if (l1 == l2) { return l1; } l2 = l2->next; } l1 = l1->next; } return NULL; }
13. 设计链表
代码实现:
🤞14. 从链表中移除节点
代码实现:
方法一:从前往后遍历 —> 超时(时间复杂度:O(n^2)
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* removeNodes(struct ListNode *head) { struct ListNode *h = malloc(sizeof(struct ListNode)); // 虚拟头节点 h->next = head; struct ListNode *p = head; // 遍历指针 struct ListNode *pre = h; // 遍历指针的前驱节点 struct ListNode *pp = NULL; // 寻找p右侧是否有比p大的节点 while (p) { pp = p->next; while (pp) { if (pp->val > p->val) { break; } pp = pp->next; } if (pp == NULL) { // 没有找到p右侧比p大的节点 pre = p; p = p->next; } if (pp != NULL) { // 找到了 // 移除p pre->next = p->next; p->next = NULL; free(p); p = pre->next; } } return h->next; }
方法二:反转链表,如果当前节点值小于前一个节点的值,则移除,最后再反转链表 时间复杂度:O(n)
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* reverse(struct ListNode *head) { if (head == NULL || head->next == NULL) { return head; } struct ListNode *tail = head->next; struct ListNode *new_head = reverse(head->next); head->next = tail->next; tail->next = head; return new_head; } struct ListNode* removeNodes(struct ListNode *head) { // 反转链表 head = reverse(head); struct ListNode *pre = head; struct ListNode *p = head->next; while (p) { if (p->val < pre->val) { // 移除 pre->next = p->next; p->next = NULL; free(p); p = pre->next; } else { pre = p; p = p->next; } } // 反转链表 head = reverse(head); return head; }
方法三:递归 时间复杂度:O(n)
- 该节点为空,那么递归函数返回空指针
- 该节点不为空,那么先对它的右侧节点进行移除操作,得到一个新的子链表,如果子链表的表头节点值大于该节点的值,那么移除该节点,否则将该节点作为子链表的表头节点,最后返回该子链表
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* removeNodes(struct ListNode *head) { if (head == NULL || head->next == NULL) { return head; } head->next = removeNodes(head->next); if (head->next->val > head->val) { return head->next; } else { return head; } }
🤞15. 合并两个有序链表
代码实现:
方法一:递归
struct ListNode* mergeTwoLists(struct ListNode *list1, struct ListNode *list2) { if (list1 == NULL) { return list2; } else if (list2 == NULL) { return list1; } else if (list1->val < list2->val) { list1->next = mergeTwoLists(list1->next, list2); return list1; } else { list2->next = mergeTwoLists(list1, list2->next); return list2; } }
方法二:常规解法 + 设置虚拟头结点
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* mergeTwoLists(struct ListNode *list1, struct ListNode *list2) { if (list1 == NULL) { return list2; } if (list2 == NULL) { return list1; } struct ListNode *head = malloc(sizeof(*head)); // 设置虚拟头结点 struct ListNode *tail = head; // 尾指针 while (list1 && list2) { if (list1->val < list2->val) { tail->next = list1; list1 = list1->next; } else { tail->next = list2; list2 = list2->next; } tail = tail->next; tail->next = NULL; } if (list1) { tail->next = list1; } if (list2) { tail->next = list2; } struct ListNode *result = head->next; head->next = NULL; free(head); return result; }
方法三:常规解法 + 不设置虚拟头结点
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* mergeTwoLists(struct ListNode *list1, struct ListNode *list2) { if (list1 == NULL) { return list2; } if (list2 == NULL) { return list1; } struct ListNode *head = NULL; // 头 struct ListNode *tail = NULL; // 尾 while (list1 && list2) { if (list1->val < list2->val) { if (head == NULL) { // 从无到有 head = list1; tail = list1; list1 = list1->next; } else { // 从少到多 tail->next = list1; list1 = list1->next; tail = tail->next; tail->next = NULL; } } else { if (head == NULL) { // 从无到有 head = list2; tail = list2; list2 = list2->next; } else { // 从少到多 tail->next = list2; list2 = list2->next; tail = tail->next; tail->next = NULL; } } } if (list1) { tail->next = list1; } if (list2) { tail->next = list2; } return head; }
🤞16. 快乐数
代码实现:
快慢指针
int getNext(int x) { int sum = 0; while (x) { int bit = x % 10; sum += bit * bit; x = x / 10; } return sum; } // 快慢指针 bool isHappy(int n) { int slow = n, fast = n; // slow = getNext(slow); // fast = getNext(getNext(fast)); // while (slow != fast && fast != 1) { // slow = getNext(slow); // fast = getNext(getNext(fast)); // } do { slow = getNext(slow); fast = getNext(getNext(fast)); } while (slow != fast && fast != 1); return fast == 1; }
🤞17. 旋转链表
代码实现:
方法一:在原链表中找到旋转之后的首尾,改变指向
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* rotateRight(struct ListNode *head, int k) { if (k == 0 || head == NULL || head->next == NULL) { return head; } int n = 1; // 统计链表节点数量 struct ListNode *p = head; while (p->next != NULL) { // 循环使p指向尾 p = p->next; n++; } int add = n - k % n; if (add == n) { return head; } p->next = head; // 将尾连接头 while (add--) { // 让p指向最终移动后的尾 p = p->next; } struct ListNode *ret = p->next; // ret指向最终移动后的头 p->next = NULL; return ret; }
方法二:反转链表
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ // 反转链表 struct ListNode* reverse(struct ListNode *head) { if (head == NULL || head->next == NULL) { return head; } struct ListNode *tail = head->next; struct ListNode *new_head = reverse(head->next); head->next = tail->next; tail->next = head; return new_head; } struct ListNode* rotateRight(struct ListNode *head, int k) { if (head == NULL || head->next == NULL || k == 0) { return head; } int len = 0; // 统计链表结点个数 struct ListNode *p = head; while (p) { len++; p = p->next; } int n = k % len; if (n == 0) { // 向右移动 n 个位置 return head; } // 翻转整个链表 head = reverse(head); struct ListNode *p1 = head, *p2; // p1指向前段待翻转区间的尾 p2指向后段待翻转区间的头 while (n - 1) { p1 = p1->next; n--; } p2 = p1->next; // p2指向后段待翻转区间的头 p1->next = NULL; // 翻转前段区间,head变尾,p1变头 reverse(head); // 翻转后段区间,将头赋值给p2 p2 = reverse(p2); head->next = p2; return p1; }
🤞18. K 个一组翻转链表
代码实现:
方法一:递归
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ void reverse(struct ListNode *head) { if (head == NULL || head->next == NULL) { return; } struct ListNode *tail = head->next; reverse(head->next); head->next = tail->next; tail->next = head; } struct ListNode* reverseKGroup(struct ListNode *head, int k) { if (head == NULL || head->next == NULL || k == 1) { return head; } // 判断剩下的节点数量是否足够 int n = 0; struct ListNode *p = head; // 遍历指针,指向第k+1个 struct ListNode *pre = NULL; // 遍历指针前驱节点,指向第k个节点 while (p) { pre = p; p = p->next; n++; if (n == k) { break; } } if (n != k) { // 后面没有k个节点,直接返回head return head; } pre->next = NULL; // 翻转, head变尾,pre变头 reverse(head); head->next = p; head->next = reverseKGroup(p, k); return pre; }
方法二:迭代—模拟
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ void reverse(struct ListNode *head) { if (head == NULL || head->next == NULL) { return; } struct ListNode *tail = head->next; reverse(head->next); head->next = tail->next; tail->next = head; } struct ListNode* reverseKGroup(struct ListNode *head, int k) { struct ListNode *new_haed = malloc(sizeof(struct ListNode)); // 虚拟头节点 new_haed->next = head; struct ListNode *h = new_haed; // h:指向每次翻转之后的尾节点,用于连接下次翻转的头节点 struct ListNode *p = head; // p:遍历指针,指向第k+1个节点,每次要翻转区间的头 struct ListNode *pre = NULL; // pre:遍历指针的前驱节点,指向第k个节点,每次要翻转的尾 while (1) { int n = 0; while (p) { pre = p; p = p->next; n++; if (n == k) { break; } } if (n != k) { break; } pre->next = NULL; h->next = NULL; // 反转,head变尾,pre变头 reverse(head); h->next = pre; head->next = p; h = head; // h指向每次翻转区间的尾 head = p; // head:每次要翻转区间的头,用于翻转 } return new_haed->next; }