Day3 2020.07.19 & 2020.07.20
1.merge-two-sorted-lists
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(!l1&&!l2) return NULL;
if(!l1&&l2) return l2;
if(l1&&!l2) return l1;
ListNode* head=new ListNode(1);
ListNode* p=head;
while(l1&&l2){
if(l1->val<=l2->val){
p->next=l1;
l1=l1->next;
}else{
p->next=l2;
l2=l2->next;
}
p=p->next;
}
if(!l1) p->next=l2;
if(!l2) p->next=l1;
return head->next;
}
};
2.partiton-list
给出一个链表和一个值x,以x为参照将链表划分成两部分,使所有小于x的节点都位于大于或等于x的节点之前。两个部分之内的节点之间要保持原始的相对顺序。
例如:
给出1->4->3->2->5->2和x = 3,
返回1->2->2->4->3->5.
**我自己的想法:**错误理解了题目的意思,这题就是将大于等于x的元素放在小于x的元素的后面,但是因为最后还加了一句,两个部分之内的节点之间要保持原始的相对顺序,以为是:4->2->1->3->5->2,输出2->4->2->1->3->5,但其实是输出:2->1->2->4->3->5。
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
//分为两种情况:
/*第一种,链表中有等于x的元素。
则需要将后半部分小于x的元素插入的前半部分第一个大于x的元素之前,且后半部分插入也要保持之前的相对顺序*/
/*第二种,链表中没有等于x的元素。
则需要将所有小于x的元素插入到第一个大于x的元素之前,都要保持原始的相对顺序*/
if(!head) return head;
ListNode* p=head;
while(p){
if(p->val==x)
break;
else
p=p->next;
}
//第一种情况
if(p&&p->val==x){
ListNode* btx=new ListNode(-1);//找前半部分中第一个大于x的元素,btx指向它的前一个元素,如果没有则btx->next=p
btx->next=head;
while(btx->next!=p){
if(btx->next->val>x)
break;
else
btx=btx->next;
}
ListNode* ltx=p;//找后半部分小于x的元素,尾插入到btx之后
ListNode* temp;
while(ltx->next&&btx!=p){
if(ltx->next->val<x){
temp=ltx->next;
ltx->next=ltx->next->next;
temp->next=btx->next;
btx->next=temp;
btx=btx->next;
}else
ltx=ltx->next;
}
return head;
}else{ //第二种情况
ListNode* btx_first=new ListNode(-1);//指向大于x的元素
ListNode* ltx_first=new ListNode(-1);//指向小于x的元素
ListNode* btx=btx_first;
ListNode* ltx=ltx_first;
ListNode* temp=head;
while(temp&&btx&<x){
if(temp->val>x) {
btx->next=temp;
btx=btx->next;
}
else{
ltx->next=temp;
ltx=ltx->next;
}
temp=temp->next;
}
ltx->next=btx_first->next;
return ltx_first->next;
}
}
};
LeetCode上的想法:
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode* before_head=new ListNode(0);
ListNode* before=before_head;
ListNode* after_head=new ListNode(0);
ListNode* after=after_head;
while(head!=NULL){
if(head->val<x){
before->next=head;
before=before->next;
}else{
after->next=head;
after=after->next;
}
head=head->next;
}
after->next=NULL;
before->next=after_head->next;
return before_head->next;
}
};
3.sort-list
== 在O(n log n)的时间内使用常数级空间复杂度对链表进行排序。==
解题思路:
- 使用快慢指针将链表一分为二(getMid),对两段分别使用递归排序(sortList)。
- 将排序好的链表链接起来,使用三指针
class Solution {
public:
//排序算法
ListNode* merge(ListNode* first,ListNode* second){
if(first==NULL) return second;
if(second==NULL) return first;
ListNode* res=new ListNode(0);
ListNode* cur=res;
while(first&&second){
if(first->val<second->val){
cur->next=first;
cur=cur->next;
first=first->next;
}else{
cur->next=second;
cur=cur->next;
second=second->next;
}
}
if(first) cur->next=first;
if(second) cur->next=second;
return res->next;
}
//将链表平分为两段
ListNode* getMid(ListNode* head){
ListNode* slow=head,*fast=head->next;
while(fast!=NULL&&fast->next!=NULL){
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
ListNode* sortList(ListNode* head) {
if(head==NULL||head->next==NULL)
return head;
ListNode* first=head,*second=NULL,*mid=getMid(head);
//将链表分成两半之后递归
second=mid->next;
mid->next=NULL;
first = sortList(first);
second = sortList(second);
return merge(first,second);
}
};
4.reorder-list
将给定的单链表L: L 0→L 1→…→L n-1→L n,
重新排序为: L 0→L n →L 1→L n-1→L 2→L n-2→…
要求使用原地算法,并且不改变节点的值
解题思路:先将链表分为两个子链表,然后将第二个子链表翻转之后与前一个子链表间隔插入。
class Solution {
public:
//先将链表分为两个子链表,然后将第二个子链表翻转之后与前一个子链表间隔插入
ListNode* reverseList(ListNode *head){
if(!head||!head->next) return head;
ListNode* tail=head;
ListNode* temp=head;
while(temp){
temp=tail->next->next;
tail->next->next=head;
head=tail->next;
tail->next=temp;
}
return head;
}
ListNode* getMid(ListNode* head){
if(!head||!head->next) return head;
ListNode* slow=head,* fast=head->next;
while(fast&&fast->next){
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
void reorderList(ListNode *head) {
if(!head||!head->next) return;
ListNode* first=head,* second=head,* mid=getMid(head);
second=mid->next;
mid->next=NULL;
second=reverseList(second);
ListNode* p=new ListNode(0);//Notice:p若指向head,在第一次p->next=first即head就会形成一个环,导致循环无法退出
int tag=-1;
while(first&&second){
if(-1==tag){
p->next=first;
first=first->next;
}else{
p->next=second;
second=second->next;
}
tag*=-1;
p=p->next;
}
if(!first) p->next=second;
if(!second) p->next=first;
}
};
5.linked-list-circle
判断给定的链表中是否有环。扩展:你能给出不利用额外空间的解法么?
解题思路:使用快慢指针,快指针fast每次移动2个节点,慢指针slow每次移动1个节点,如果快指针能够追上慢指针,那就说明其中有一个环,否则不存在环。
class Solution {
public:
bool hasCycle(ListNode *head) {
if(head==NULL||head->next==NULL) return false;
ListNode* slow=head,*fast=head->next;
while(fast&&fast->next){
slow=slow->next;
fast=fast->next->next;
if(slow==fast)
return true;
}
return false;
}
};
6.linked-list-circle ii
== 对于一个给定的链表,返回环的入口节点,如果没有环,返回null。拓展:你能给出不利用额外空间的解法么?==
解题思路:当判断完当前链表有环之后,将两指针分别放在链表头和相遇位置,并改为相同速度推进,则两指针在环开始位置相遇。(可以推出,如将此时两指针分别放在起始位置和相遇位置,并以相同速度前进,当一个指针走完距离a时,另一个指针恰好走出 绕环n-1圈加上c的距离。)
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(!head) return NULL;
ListNode* slow=head,*fast=head;
//首先判断是否有环
while(fast&&fast->next){
slow=slow->next;
fast=fast->next->next;
if(slow==fast) break;
}
if(!fast||!fast->next) return NULL;
slow = head;
while(slow != fast){
slow = slow->next;
fast = fast->next;
}
return slow;
}
};
7.copy-list-with-random-pointer
== 现在有一个这样的链表:链表的每一个节点都附加了一个随机指针,随机指针可能指向链表中的任意一个节点或者指向空。请对这个链表进行深拷贝。==
解题思路:首先拷贝链表中的结点和随机指针(直接指向原链表中的结点),然后将随机指针指向的结点从原链表分离到拷贝链表,分离的时候要保证原链表不被改变。
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
if(!head) return head;
RandomListNode* copy,*p;
//将每一个结点复制并插入原始结点后面
for(p=head;p;p=p->next){
copy=new RandomListNode(p->label);
copy->next=p->next;
p->next=copy;
p=p->next;
}
//复制随即指针
for(p=head;p;p=copy->next){
copy=p->next;
copy->random=(p->random?p->random->next:NULL);
}
//将链表拆分为两个
for(p=head,head=p->next,copy=p->next;p;){
p->next=copy->next;
p=p->next;
copy->next=(p?p->next:NULL);
copy=copy->next;
}
return head;
}
};
8.evaluate-reverse-polish-notation
计算逆波兰式(后缀表达式)的值,运算符仅包含"+","-","*“和”/",被操作数可能是整数或其他表达式。
解题思路:
- 从左到右依次逐个扫描后缀表达式;
- 若是数字,则将字符转换成数字后存入栈;
- 若是运算符,则获取并删除两个栈顶元素,对得到的值进行相应运算并入栈;(注意后出栈的元素是第一操作数,先出栈的是第二操作数)
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int>* s=new stack<int>();
for(vector<string>::iterator it=tokens.begin();it!=tokens.end();it++){
if(*it=="+"){
if(!s->empty()){
int second=s->top();
s->pop();
int first=s->top();
s->pop();
s->push(first+second);
}
}
if(*it=="-"){
if(!s->empty()){
int second=s->top();
s->pop();
int first=s->top();
s->pop();
s->push(first-second);
}
}
if(*it=="*"){
if(!s->empty()){
int second=s->top();
s->pop();
int first=s->top();
s->pop();
s->push(first*second);
}
}
if(*it=="/"){
if(!s->empty()){
int second=s->top();
s->pop();
int first=s->top();
s->pop();
s->push(first/second);
}
}
if(*it!="+"&&*it!="-"&&*it!="*"&&*it!="/"){
s->push(atoi((*it).c_str()));
}
}
if(!s->empty()) return s->top();
delete s;
}
};
9.palindrome-linked-list
请判断一个链表是否为回文链表。你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
== 记住整个链表翻转的过程==
ListNode* tail=nullptr;
while(head){
ListNode* temp=head->next;
head->next=tail;
tail=head;
head=temp;
}
class Solution {
public:
bool isPalindrome(ListNode* head) {
if(!head||!head->next) return true;
ListNode* fast=head,*slow=head,*second=nullptr;
while(fast&&fast->next){
slow=slow->next;
fast=fast->next->next;
}
//翻转后半部分的链表
while(slow){
ListNode* temp=slow->next;
slow->next=second;
second=slow;
slow=temp;
}
while(head&&second){
if(head->val!=second->val) return false;
head=head->next;
second=second->next;
}
return true;
}
};