因为复习的缘故,一开始按tag做起,难度也是从简单到困难。
237. Delete Node in a Linked List
这一题题目看了半天没看懂,实际上比较简单,就是给定一个List结点,从链表中删除他,代码如下:
<span style="font-size:18px;">//My code
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
ListNode* nextnode = node->next;
node->val = nextnode->val;
node->next = nextnode->next;
delete(nextnode);
}
};</span>
234. Palindrome Linked List
<span style="font-size:18px;">//My code
//功能:判断一单向链表是否是回文链表(从前往后与从后往前读取内容一样),若是返回ture,否则返回false.
// 要求时间复杂度为O(n),控件复杂度为O(1).
ListNode* ReverseList(ListNode* head) //返回反转之后的头结点
{
ListNode* p1 = head;
ListNode* p2 = head->next;
ListNode* p3;
while(p2)
{
p3 = p2->next;
p2->next = p1;
p1 = p2;
p2 = p3;
}
head->next = NULL;
return p1;
}
bool isPalindrome(ListNode* head) {
if(head == NULL || head->next == NULL)
return true;
ListNode* fast = head;
ListNode* slow = head;
ListNode* right;
while(fast&&fast->next)
{
fast = fast->next->next;
slow = slow->next;
}
if(fast == NULL) //链表节点数为偶数
{
//慢指针正好指向后面一部分,将后面一部分反转过来
right = ReverseList(slow);
}
else //链表节点数为奇数
{
//慢指针正好指向中间的结点,该节点无需反转
right = ReverseList(slow->next);
}
while(head && right)
{
if(head->val != right->val)
{
return false;
}
head = head->next;
right = right->next;
}
return true;
}</span>
<span style="font-size:18px;">//others code
ListNode* reverseList(ListNode* head) {
ListNode* pre=NULL;
ListNode* next=NULL;
while(head!=NULL){
next=head->next;
head->next=pre;
pre=head;
head=next;
}
return pre;
}
bool isPalindrome(ListNode* head) {
if(head==NULL||head->next==NULL)
return true;
ListNode* slow=head;
ListNode* fast=head;
while(fast->next!=NULL&&fast->next->next!=NULL){
slow=slow->next;
fast=fast->next->next;
}
slow->next=reverseList(slow->next);
slow=slow->next;
while(slow!=NULL){
if(head->val!=slow->val)
return false;
head=head->next;
slow=slow->next;
}
return true;
}</span>
总结:此题思考了很长时间想不出能再O(n)的时间复杂度与O(1)的控件复杂度内解决的办法,最后参考网上的说明才知道了最常用的方法。首先是采用快慢指针遍历的方式迅速找到中点,这里快指针跑的节点数是慢指针的两倍,因此快指针到达链尾时慢指针正好在链中附近,这里说附近的原因就是因为链节点数的不同,若为偶数结点,快指针到链尾时,快指针正好在链中的下一个结点,若是奇数结点,快指针到链尾时慢指针正好在链中。因此我的代码中对这两种进行了分类处理。在找到链中元素后,将链中后面的元素反转,这样反转以后再跟头结点遍历一遍作比较就知道是否是回文链表了。这里看到别人的代码唯一的区别就是他没有对链表的奇偶数进行判别,这也是高明的地方。看while循环里面我的判断是fast&&fast->next;而他的代码里是fast->next&&fast->next->next。这回导致什么呢,这会导致在链表为偶数结点时,快指针到链尾后,慢指针还在中间靠前的那个结点上,这样用下面这两行代码就解决了链表是奇偶数判断的问题。
<span style="font-size:18px;">slow->next=reverseList(slow->next);
slow=slow->next;</span>
203. Remove Linked List Elements
//My code
//功能:删除单链表中的重复结点,可以有多个重复
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* pre = NULL;
ListNode* cur = head;
ListNode* temp;
while(cur)
{
if(cur->val == val)
{
if(cur == head) //是头结点
{
head = cur->next;
temp = cur;
cur = cur->next;
free(temp);
}
else
{
temp = cur;
cur = cur->next;
pre->next = cur;
free(temp);
}
}
else
{
pre = cur;
cur = cur->next;
}
}
return head;
}
};
总结:这题是典型的删除链表指定值结点的题,如果说稍微有些不同的话,这题的链表里允许有重复结点。
160. Intersection of Two Linked Lists
//My code
//功能:求两个链表的第一个公共结点
/**
* 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* pA = headA;
ListNode* pB = headB;
int lineA = 0, lineB = 0;
while(pA)
{
lineA++;
pA = pA->next;
}
while(pB)
{
lineB++;
pB = pB->next;
}
if(lineA == 0 && lineB == 0)
return NULL;
pA = headA;
pB = headB;
if(lineA == lineB)
{
while(pA && pB)
{
if(pA->val == pB->val)
return pA;
pA = pA->next;
pB = pB->next;
}
}
else if(lineA > lineB)
{
int space = lineA - lineB;
while(space)
{
pA = pA->next;
space--;
}
while(pA && pB)
{
if(pA->val == pB->val)
return pA;
pA = pA->next;
pB = pB->next;
}
}
else if(lineB > lineA)
{
int space = lineB - lineA;
while(space)
{
pB = pB->next;
space--;
}
while(pA && pB)
{
if(pA->val == pB->val)
return pA;
pA = pA->next;
pB = pB->next;
}
}
return NULL;
}
};
//others code
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
{
ListNode *p1 = headA;
ListNode *p2 = headB;
if (p1 == NULL || p2 == NULL) return NULL;
while (p1 != NULL && p2 != NULL && p1 != p2) {
p1 = p1->next;
p2 = p2->next;
if (p1 == p2) return p1;
if (p1 == NULL) p1 = headB;
if (p2 == NULL) p2 = headA;
}
return p1;
}
总结:这道题一开始也没想到什么好的解决办法,后来参考网上的资料知道了大致的思路,先遍历一遍统计两个链表的长度,若同样长的话一起遍历下去找到首个相同的结点,若不一样长,长的那个链表先遍历两链表长度之差个结点后,两链表编程一样长在一起遍历找交叉结点。
141. Linked List Cycle
//My code
//功能:检测一个链表是否是循环链表
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head == NULL || head->next == NULL)
return false;
ListNode* fastNode = head;
ListNode* slowNode = head;
while(fastNode->next && fastNode->next->next)
{
fastNode = fastNode->next->next;
slowNode = slowNode->next;
if(fastNode == slowNode)
return true;
}
return false;
}
};
总结:这一题是很简单的,算法的思路也很明确,判断链表是否是循环链表比较快速的方式那就是快慢指针了,算出来的结果与别人的也相差无几。就是不要忘记最开始的判断情况。
83. Remove Duplicates from Sorted List
//My code
//功能:从已排好序的链表中删除重复的结点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if(head == NULL || head->next == NULL)
return head;
ListNode* p1 = head;
ListNode* p2 = head->next;
ListNode* temp;
while(p2)
{
if(p1->val == p2->val)
{
temp = p2;
p2 = p2->next;
p1->next = p2;
free(temp);
}
else
{
p1 = p2;
p2 = p2->next;
}
}
return head;
}
};
总结:类似于删除单链表结点的扩展,还是比较简单的。
24. Swap Nodes in Pairs
//迭代法
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy=new ListNode(0);
dummy->next=head;
ListNode* prev=dummy;
while(head &&head->next)
{
ListNode* nn=head->next->next;
prev->next=head->next;
head->next->next=head;
head->next=nn;
prev=head;
head=nn;
}
return dummy->next;
}
};
//迭代法
ListNode* swapPairs1(ListNode* head) {
if (!head || !(head->next))
return head;
ListNode *res = head->next;
head->next = swapPairs(res->next);
res->next = head;
return res;
}
总结:这道题没做出来,似乎很不喜欢做这类题目,参考的别人的两种方法,下面来分析分析:
迭代法中,插入了一个头结点,并将prev指针指向他,在每次迭代中,始终保持prev在head的后面,然后head前进两格,再做处理。可参考下面的示意图。
ListNode* nn=head->next->next;①
prev->next=head->next;②
head->next->next=head;③
head->next=nn;④
prev=head;⑤
head=nn;⑥