下午一点四十开始第二个7题✔
8. 回文链表(234)
解题思路(边界条件要注意
设置快慢指针,快指针走到尾慢指针刚好到中点,然后前半段和后半段就一一比较就行
用栈
慢指针在走的时候顺便把元素给存入到栈中
不用栈
不用栈的话就在找到中点之后将后半段链表进行翻转
手写代码,注释思路
- 用栈
class Solution{
public:
bool isPalindrome(ListNode*head){
ListNode *fast = head;
ListNode* slow = head;
stack<int> st{{head->val}};
if(!head || !head->next) return true;
while(fast->next && fast->next->next) //这边停止条件
{
fast = fast->next->next;
slow = slow->next;
st.push(slow->val);//先走再放和先放再走跟原来节点有没有初始化是有关系的,也跟停止条件有关系
}
if(!fast->next) st.pop();
while(slow->next) //why这边的停止条件
{
slow = slow->next;
if(slow->val != st.top()) return false;
st.pop();
}
return true;
}
};
- follow up要求为原地排序,不让用栈
public:
bool isPalindrome(ListNode*head){
//还是先设置快慢指针
if(!head ||!head->next) return true;
ListNode *fast = head;
ListNode *slow = head;
while(fast->next && fast->next->next)//fast的目标状态是在最后一个或者倒数第二个的位置,循环条件是 !(目标状态时的条件),这边的目标状态是->next == null 或者->next->next == null,
{
fast = fast->next->next;
slow = slow->next;
}
//slow到中间了,开始倒置链表
ListNode* first = slow->next;
while(first->next)//“head”到末尾了就停止,就是head->next = null,那么否定就是head->next,即slow->next->next
{//slow first cur houmian
ListNode* cur = first->next;
first->next = cur->next;
cur->next = slow->next;
slow->next = cur;
}
//开始比较,slow往后走,
while(slow->next)
{
slow = slow->next;
if(head->val != slow->val) return false;
head = head->next;
//slow = slow->next;
}
return true;
}
};
//!!!通过了
是否AC, 什么问题
- !!!边界问题,在循环里放什么停止条件!!!
while(满足的条件){
迭代,条件改变
}
判断—> 操作,改变—>再判断……最后一次迭代,判断不满足,跳出循环
写代码的时候心里肯定是有一个期望的,期望它到达什么状态时就跳出循环,即目标状态时是刚好不满足这个条件的
题中,fast最后的状态要么在最后一个位置fast->next == null
要么在倒数第二个位置,它没法走两步了fast->next->next ==null
,所以我们第一次期望停止的条件就是fast指针走到最后状态的位置时刚好条件不满足,所以我们的循环条件就是那两个状态的否while(fast->next && fast->next->next)
ok,来看一下第二个以slow为标准的循环,我们期待的是slow到最后一个节点,比较之后就不满足情况了,即slow->next = null
,就是最后一个节点的标志,所以我们正常循环时候的条件就应该是这个条件的否while(slow-next)
至于初始条件的话,我觉得应该更多跟内部代码行的顺序相关。
///
done,感觉理清楚了,多做题锻炼思维习惯,以后面试题的时候可以快速解决边界。
9. 分割链表(725)
把链表分隔成 k 部分,每部分的长度都应该尽可能相同,排在前面的长度应该大于等于后面的。Input:
root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
Explanation:
The input has been split into consecutive parts with size difference at most 1, and earlier parts are a larger size than the later parts.
解题思路
1,获取链表长度,除以k获得每个链表的理想长度以及其不理想的余数,余数从头开始一个一个分1
2,由1获得分割链表的长度,然后就开始分割
3,考虑k>链表长度,那么从左到右1,剩余NULL补充
手写代码,注释思路
class Solution {
public:
vector<ListNode*> splitListToParts(ListNode* root, int k) {
//返回的是一个vector,要把每一个链表的头节点放入到容器中
int len = 0; int avg = 0; int ext = 0;
vector<ListNode*> res(k);
while(root->next) len++;
avg = len / k; ext = len % k;
//前面ext组每个链表是avg+1个节点,后面k-ext组是avg个
//怎么分链表?最后一个节点指向null,头节点记得保留就ok吧
//ListNode *guard = root; //待会就把这个哨兵放入到结果集中就行了
for(int i = 0; i<k; ++i)
{
res.push_back(root);
for(int j = 1; j<avg+(i<ext); ++j)//因为一开始就是有一个节点存在的,所以从1开始就好了
{
root = root->next;
}
ListNode * t = root->next;//下一个链表的头节点
root->next = NULL;//这个链表的结束位置已经标出来
root = t;
}
return res;
}
};
是否AC, 什么问题
超时,欸,我还觉得自己方法好得很(sad 什么问题?并不知道……
half hour later……
问题在这里 && root ,有可能链表的节点数不够分,后来root就等于NULL了,所以在总循环的地方for(int i = 0; i<k; ++i)
应该要补上for(int i = 0; i<k; ++i)&& root
!!! 欸,这跟链表,树的一上来就判断空或单节点一样是逻辑上最容易想到的却也总容易遗忘的,一定不要漏了
10. 链表元素按奇偶聚合(328)
Example:
Given 1->2->3->4->5->NULL,
return 1->3->5->2->4->NULL.
解题思路
将原本在奇数位置的数都放到前面,原来偶数位置的数都放到后面:
初始化pre在第一个奇数上,cur在第二个奇数上,将第二个奇数放到cur前面
然后pre,cur都分别往后移一个节点,pre永远在奇数上,cur永远在偶数上,这个主要是方法要记一下,实现起来还是ok的
1 2 3 4 5 6
p c
1 3 2 4 5 6
. .p…c
然后又将5放到p对应的3后面,就 1 3 5 2 4 6 完成了
手写代码,注释思路
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(!head || !head->next) return head;
ListNode* pre = head;
ListNode* cur = head->next;
//ok,又要测试我的临界条件了
while(cur && cur->next)//目标状态是cur变成最后一位了就是cur&&cur->next = null,最后的状态刚好不满足条件,是目标状态的否定, 空,反过来就是不空,就是有
{
ListNode *tmp = cur->next; // p c t 4
cur->next = tmp->next;
tmp->next = pre->next;
pre->next = tmp;
cur = cur->next;
pre = pre->next;
}
return head;
}
};
是否AC, 什么问题
== 否 == ,
问题1:最开始判断if(!head||!head->next) return;
又忘记写了,又一次降低提交成功率
问题2:边界条件
再一次出错,在循环比较的时候,我觉得应该是cur
到最后一个就停止,那么终止状态就是cur->next =null
,循环内的条件就应该是状态的否,就是while(cur->next)
,但是需要while(cur && cur->next
,还要保证cur存在???
嗷嗷,因为又可能出现最后一个cur->next的时候就已经是空了,比如12345这样的情况,p在3上c在5上再分别往后移一个的话c就已经是null了,所以目标状态是 == cur已经是空或者cur在最后一个,即cur->next = null || cur=NULL==,循环条件取反就是cur->next && cur
!!! 耶,总结的循环临界值问题成功√
七点了……觉得所有计划的最后1/3都应该放到下个月去完成了,欸,怪自己做力扣开始得太晚了,希望接下来会做题稍微有感觉一点(虽然觉得不太可能🙂),但是不轻松也要坚持呀2020-04-02
终于意义上的自己完成AC代码,鼓励自己!加油!慢一点也是没有办法的事谁要开始晚呢,不要叹息已经过去的时间,抓紧当下啦 2020-04-04