ListNode* removeNthFromEnd(ListNode* head, int n) {
if (!head) return NULL;
ListNode *first = head;
ListNode *second = first;
/*first指针先走n步,此时若first为空,则要删除的节点是首节点*/
for (int i = 0; i < n; i++) {
first = first->next;
}
if (!first) {
return head->next;
}
/*两个指针同时走,当first->next为空时,second指向的下一个节点即为倒数第n个节点*/
while (first->next) {
first = first->next;
second = second->next;
}
second->next = second->next->next;
return head;
}
ListNode* middleNode(ListNode* head) {
if(!head) return NULL;
ListNode *first = head, *second = head;
while(first->next){
first = first->next;
second = second->next; // 让second提前走,可保证节点数为偶数时,second指向中间靠后节点
if(first->next) first = first->next;
}
return second;
}
#include
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
ListNode* MakeList();
void ListAppend(ListNode*, int);
ListNode* ListMakeCycle(ListNode*, int);
void Print(ListNode* head, ListNode* start);
bool hasCycle(ListNode *head);
int main() {
ListNode *head = MakeList();
int value;
cout << "Please input the value of the node : " << endl;
while (cin >> value) {
ListAppend(head, value);
if (cin.get() == '\n') {
break;
}
}
cout << "Please choose the start node of the cycle : " << endl;
int n;
cin >> n;
ListNode *start = ListMakeCycle(head, n);
cout << "The linked list with cycle : " << endl;
Print(head, start);
bool IsCycle = hasCycle(head->next);
cout << "\nIs cycle ? " << IsCycle << endl;
return 0;
}
/* 生成链表的表头 */
ListNode* MakeList() {
ListNode *head = new ListNode(-1);
return head;
}
/* 在链表尾部插入节点 */
void ListAppend(ListNode* head, int value) {
if (!head) return;
ListNode *tmp = head;
while (tmp->next) {
tmp = tmp->next;
}
ListNode *node = new ListNode(value);
tmp->next = node;
}
/* 将链表的最后一个节点接到第n个节点,生成环,并返回环的起点 */
ListNode* ListMakeCycle(ListNode* head, int n) {
if (!head || !n) return NULL;
ListNode *end = head->next;
ListNode *start = end;
int count = 1;
while (end->next) {
if (count != n) {
start = start->next;
count++;
}
end = end->next;
}
end->next = start;
//cout << "\nstart node : " << start->val << endl;
return start;
}
/* 打印链表,并将环打印两遍 */
void Print(ListNode *head, ListNode *start) {
if (!head) return;
ListNode *tmp = head->next;
int count = 0;
while (true) {
if (tmp == start) {
count++;
if (count == 3) {
break;
}
}
cout << tmp->val << ' ';
tmp = tmp->next;
}
}
/* 判断链表是否有环 */
bool hasCycle(ListNode *head) {
if (!head || !head->next) return false;
ListNode *slow = head;
ListNode *fast = head->next;
while (fast != NULL && fast->next != NULL) {
fast = fast->next->next; // 快指针每次走两步
slow = slow->next; // 慢指针每次走一步
if (fast == slow) {
return true;
}
}
return false;
}
输出结果:
图片来源:(Leetcode 142)Linked List Cycle (II) (快慢指针详解)
下面寻找环的起点。快指针继续指向两个指针第一次相遇的节点c,将满指针指向链表的首个节点h,然后两个指针每次同步向前移动一个节点,当两个指针再次相遇时,相遇的节点即为环的起点。
ListNode *detectCycle(ListNode *head) {
if (!head || !head->next) return NULL;
ListNode *fast = head;
ListNode *slow = fast;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
if (fast == slow) { // 快慢指针相遇,则链表有环
break;
}
}
if (!fast || !fast->next) { // 链表无环(节点数为奇数时,fast为空;为偶数时,fast->next为空)
return NULL;
}
slow = head; // 快指针从两个指针相遇的地方出发,慢指针从链表的首个节点出发,同步移动
while (fast != slow) { // 两个指针再次相遇的节点即为环的起点
fast = fast->next;
slow = slow->next;
}
return fast;
}
上图适用于翻转链表中的K个节点。如上图所示,指针new指向链表中已翻转部分的首个节点,指针old指向链表中未翻转链表的首个节点。指针向前遍历的过程中,依次将old指向new,逐个翻转节点,直至遍历结束,即old为空。(上图中的链表是带头节点的,LeetCode中的链表均不带头节点,编写代码时需注意。)
ListNode* reverseList(ListNode* head) {
ListNode *rev = NULL; // 指向链表中已翻转部分的头部
ListNode *unrev = head; // 指向链表中未翻转部分的头部
while (unrev) {
ListNode *tmp = unrev->next; // 保存未翻转部分头节点的位置
unrev->next = rev; // 节点翻转
rev = unrev; // 更新rev
unrev = tmp; // 更新unrev
}
return rev;
}
在本题中需要注意的是rev指针的初始位置,rev初始位置应指向NULL而不是链表的首个节点。若rev初始位置为链表的首个节点,由于其不为空,则整个链表翻转完成后,以上图为例,最后一个节点1的下个节点不是空节点,而是翻转之前的链表中1的下一个节点2,即翻转后链表为6,5,4,3,2,1,2,1,2,1… 。(自己就踩了这个坑。。。。。。)
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode *rev = new ListNode(-1); // 指向链表中已翻转部分的头部
rev->next = head;
int num = 0;
while (num < m - 1) {
if (rev->next) {
rev = rev->next;
num++;
}
}
ListNode *flag = rev; // 此时rev指向待翻转节点的前一个节点
ListNode *unrev = rev->next; // 指向链表中未翻转部分的头部
int count = 0;
int k = n - m + 1;
while (count < k) {
ListNode *tmp = unrev->next; // 保存未翻转部分头节点的位置
unrev->next = rev; // 节点翻转
rev = unrev; // 更新rev
unrev = tmp; // 更新unrev
count++;
}
flag->next->next = unrev;
flag->next = rev;
if (m == 1) {
return flag->next;
}
else {
return head;
}
}
ListNode* swapPairs(ListNode* head) {
ListNode *ehead = new ListNode(-1);
ehead->next = head;
ListNode *pre = ehead, *cur = head;
while (cur && cur->next) {
pre->next = cur->next;
cur->next = pre->next->next;
pre->next->next = cur;
pre = cur;
cur = cur->next;
}
return ehead->next;
}
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode *dummy = new ListNode(-1);
dummy->next = head;
ListNode *pre = dummy, *cur = pre->next;
int len = 0;
while (cur) {
len++;
cur = cur->next;
}
cur = pre->next;
while (len >= k) {
for (int i = 1; i < k; i++) {
ListNode *t = pre->next; // 记录当前要翻转节点翻转后要指向的节点
pre->next = cur->next; // 记录下一次要翻转的节点翻转后要指向的节点(即当前要翻转的节点)
cur->next = pre->next->next; // 记录下一次要翻转的节点
pre->next->next = t; // 节点翻转:每次翻转的是cur指向的下一个节点
}
pre = cur;
cur = pre->next;
len -= k;
}
return dummy->next;
}
void reorderList(ListNode* head) {
if (!head || !head->next) return;
ListNode *fast = head, *slow = head;
while (fast->next && fast->next->next) {
slow = slow->next;
fast = fast->next->next;
} // 此时first指向链表中点
fast = slow->next; // 从fast节点开始翻转链表
ListNode *rev = NULL;
while (fast) {
ListNode *tmp = fast->next;
fast->next = rev;
rev = fast;
fast = tmp;
}
slow->next = rev;
fast = head; // 两个指针分别从头和中间向后遍历
while (slow->next && fast != slow) {
ListNode *t1 = fast->next;
ListNode *t2 = slow->next->next;
fast->next = slow->next;
fast->next->next = t1;
slow->next = t2;
fast = t1;
}
}
bool isPalindrome(ListNode* head) {
if (!head || !head->next) return true;
ListNode *fast = head, *slow = head;
while (fast->next && fast->next->next) {
fast = fast->next->next;
slow = slow->next;
}
bool isEven = false;
if (fast->next) { // fast为倒数第二个节点,则节点数量为偶数,要翻转中间节点
slow = slow->next;
isEven = true;
}
fast = head;
ListNode *rev = NULL;
while (fast != slow) { // 翻转前半个链表
ListNode *tmp = fast->next;
fast->next = rev;
rev = fast;
fast = tmp;
}
head->next = fast; // 此时rev为表头
//PrintList(rev);
if (!isEven) { // 节点数量为奇数时,要从中点的后一个节点比较
slow = slow->next;
}
while (slow) { // 比较翻转后的链表的前后半部分是否相同
if (rev->val != slow->val) {
return false;
}
else {
rev = rev->next;
slow = slow->next;
}
}
return true;
}