LeetCode刷题(二)——链表&栈和队列

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&&ltx){
                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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值