/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head==nullptr) return nullptr;
if(head->next==nullptr) return head;
ListNode * pre;
ListNode * cur;
ListNode * resH=new ListNode(0);
resH->next=head;
ListNode * res1=resH;
pre=head;
cur=head->next;
ListNode * tmp;
while(cur!=nullptr){
tmp=cur->next;
cur->next=pre;
pre->next=tmp;
res1->next=cur;
res1=pre;
pre=tmp;
if(tmp==nullptr) break;
cur=tmp->next;
}
res1=resH->next;
resH->next=nullptr;
delete resH;
return res1;
}
};
要注意用的值是否被更新过,如果要用没更新的,那要把相关的代码放在更新该值的那行前,一遍ac。题解说的是一定要画图,那也许画图了就不需要格外注意这点了。
题解代码如下:
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
dummyHead->next = head; // 将虚拟头结点指向head,这样方便后面做删除操作
ListNode* cur = dummyHead;
while(cur->next != nullptr && cur->next->next != nullptr) {
ListNode* tmp = cur->next; // 记录临时节点
ListNode* tmp1 = cur->next->next->next; // 记录临时节点
cur->next = cur->next->next; // 步骤一
cur->next->next = tmp; // 步骤二
cur->next->next->next = tmp1; // 步骤三
cur = cur->next->next; // cur移动两位,准备下一轮交换
}
return dummyHead->next;
}
};
只允许一遍遍历链表。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
int digui(ListNode* head,int n){
if(head->next==nullptr){
if(n==1) head=NULL;
return 1;
}
int tmp1= (digui(head->next,n)+1);
if(tmp1==n+1){
ListNode * tmpN=head->next;
head->next=tmpN->next;
tmpN->next=nullptr;
delete tmpN;
}
return tmp1;
}
ListNode* removeNthFromEnd(ListNode* head, int n) {
if(n==1&&head->next==nullptr) return NULL;
ListNode* nodeV= new ListNode();
nodeV->next=head;
digui(nodeV,n);
return nodeV->next;
}
};
我自己的写法是递归回溯的时候统计数量,到反过来第n个节点的时候删掉。以后最好都写由虚拟头节点的写法。我这个也是一遍遍历,只是有回溯的过程,可能不算一遍扫描。
题解的写法是快慢指针,慢指针和快指针都指向虚拟头节点,快指针先移动到n+1位置,再慢指针和快指针同时移动指导快指针指到末尾。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* slow = dummyHead;
ListNode* fast = dummyHead;
while(n-- && fast != NULL) {
fast = fast->next;
}
fast = fast->next; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点
while (fast != NULL) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
// ListNode *tmp = slow->next; C++释放内存的逻辑
// slow->next = tmp->next;
// delete nth;
return dummyHead->next;
}
};
还是想用递归写,扫了眼题解,发现可能要先把两个指针末尾对齐,然后从前往后找相等的数。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode * tmpA=headA;
ListNode * tmpB=headB;
int lenA=0;
int lenB=0;
while(tmpA!=nullptr){
tmpA=tmpA->next;
lenA++;
}
while(tmpB!=nullptr){
tmpB=tmpB->next;
lenB++;
}
tmpA=headA;
tmpB=headB;
int cha=0;
int mi=lenB;
if(lenA>lenB){
cha=lenA-lenB;
while(cha--){
tmpA=tmpA->next;
}
}
else if(lenB>lenA){
cha=lenB-lenA;
while(cha--){
tmpB=tmpB->next;
}
mi=lenA;
}
ListNode * res=new ListNode(0);
while(mi--){
if(tmpA->val==tmpB->val){
if(res->val==0)
res=tmpA;
}
else{
res->next=nullptr;
res->val=0;
}
tmpA=tmpA->next;
tmpB=tmpB->next;
}
return res;
}
};
上面是原本写的判断数值相等就选交点,那下述情况就为1了,而不是8了。
应该是判断指针是否相等tmpA==tmpB
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode * tmpA=headA;
ListNode * tmpB=headB;
int lenA=0;
int lenB=0;
while(tmpA!=nullptr){
tmpA=tmpA->next;
lenA++;
}
while(tmpB!=nullptr){
tmpB=tmpB->next;
lenB++;
}
tmpA=headA;
tmpB=headB;
int cha=0;
int mi=lenB;
if(lenA>lenB){
cha=lenA-lenB;
while(cha--){
tmpA=tmpA->next;
}
}
else if(lenB>lenA){
cha=lenB-lenA;
while(cha--){
tmpB=tmpB->next;
}
mi=lenA;
}
ListNode * res=new ListNode(0);
while(mi--){
if(tmpA==tmpB){
return tmpA;
}
tmpA=tmpA->next;
tmpB=tmpB->next;
}
return nullptr;
}
};
希望用O(1)的空间解决这个问题。
只能想到入环的地方有两个指向它的指针这个特点。题解说双指针法。
题解连接:
https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html#%E6%80%9D%E8%B7%AF
简单说,会声明一个快指针(一次移动两个)和一个慢指针(一次移动一个),快指针和慢指针都从头节点开始出发,因为相比于慢指针,快指针是一个个地移向慢指针,并且最后一定会相遇。相遇的时候一定在环内。
利用指针相遇的路程关系列一个方程,再利用快指针走的是慢指针的两倍列一个方程,就能得到,从头节点出发一个指针,从相遇节点出发一个指针,各自每次走一个节点,相遇的节点就是环形入口节点。看了题解的解释才写出来的。注:fast要判断是否指向的是nullptr,否则会尝试nullptr->next的值。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head==nullptr) return nullptr;
if(head->next==nullptr) return nullptr;
ListNode * slow=head;
ListNode * fast =head;
slow=slow->next;
fast=fast->next;
fast=fast->next;
while(fast!=nullptr&&slow!=fast){
slow=slow->next;
fast=fast->next;
if(fast==nullptr) return nullptr;
fast=fast->next;
}
if(slow!=fast) return nullptr;
ListNode * newT=head;
while(newT!=slow){
slow=slow->next;
newT=newT->next;
}
return newT;
}
};
题解写法:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
if (slow == fast) {
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2; // 返回环的入口
}
}
return NULL;
}
};