算法训练day4|24. 两两交换链表中的节点|19.删除链表的倒数第N个节点| 面试题 02.07. 链表相交| 142.环形链表II

一、24. 两两交换链表中的节点

  1. 无脑转数组暴力

不需要多思考,注意奇偶就行。空间换时间,暴力大多如此。空间O(n),时间O(n)

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(nullptr == head || nullptr == head->next){
            return head;
        }
        //暴力解
        ListNode *p = head;
        vector<int>a;
        while(nullptr != p){
            a.push_back(p->val);
            p = p->next;
        }
        int size = a.size();
        if(a.size()%2==1){
            size = a.size() - 1;
        };
        for(int i=0;i<size;i+=2){
            swap(a[i],a[i+1]);
        }
        ListNode *dummyhead = new ListNode(0);
        p = dummyhead;
        for(int i=0;i<a.size();i++){
            ListNode *q = new ListNode(a[i]);
            p->next = q;
            p = q;
        }
        p->next = nullptr;
        return dummyhead->next;
    }
};
  1. 三指针

用多指针后移要多注意边界条件,链表特别要注意空针异常。空间O(1),时间O(n)

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if(nullptr == head || nullptr == head->next){
            return head;
        }
        ListNode *dummyhead = new ListNode(0);
        ListNode *pre = dummyhead;
        dummyhead->next = head;
        ListNode *p = head , *q = head->next;
        while(nullptr != q && nullptr != p && nullptr != q->next){
            p->next = q->next;
            q->next = p;
            pre->next = q;
            pre = p;
            p = p->next;
            q = p->next;
        }
        if(nullptr == q){
            return dummyhead->next;
        }
        if(nullptr == q->next){
            p->next = nullptr;
            q->next = p;
            pre->next = q;
        }
        return dummyhead->next;    
};
};

二、19.删除链表的倒数第N个节点

  1. 暴力解

虽然很明显原题是想我用双指针来找倒数第n个节点,但是我调皮一下转数组暴力解再重新新建链表就行了,也可以原地把原数组值换了。

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        //想到一种怪的暴力解
        vector<int>array;
        ListNode *p=head;
        while(nullptr != p){
            array.push_back(p->val);
            p = p->next;
        }
        array.erase(array.begin()+array.size()-n);
        int i=0;
        ListNode *dummyhead = new ListNode(0);
        p = dummyhead;
        while(i<array.size()){
            ListNode *q = new ListNode(array[i++]);
            p->next = q;
            p = q;
        }
        return dummyhead->next;
    }
};
  1. 双指针

右指针先往前走n次,此时左指针开始同步移动,找到倒数第n个节点的前一个,删除即可,时间复杂度O(n)

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        //间隔n位的同步双指针
        if(nullptr == head->next){
            return nullptr;
        }
       ListNode *p,*pre;
       ListNode *dummyhead = new ListNode(0);
       dummyhead->next = head;
       p = dummyhead;
       pre = dummyhead;
       int i = 0;
       while(i++<n+1 ){
           p = p->next;
       } 
       while(nullptr != p){
           p = p->next;
           pre = pre->next;
       }
       p = pre ->next;
       pre->next = pre->next->next;
       delete p;
        return dummyhead->next;
    }
};

三、面试题 02.07. 链表相交

双指针

不难,这题数据结构做过很多遍了,不上变数组了,但是这题比的是节点,不是节点值,似乎不能用数组。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int i=0,j=0;
        ListNode *p,*q;
        p=headA;
        while(NULL != p){
            i++;
            p = p->next;
        }
        p = headB;
        while(NULL != p){
            j++;
            p = p->next;
        }
        int k=0;
        p=headA;
        q=headB;
        if(i>j){
            
            while(k++<(i-j)){
                p = p->next;
            }
        }else{
            
            while(k++<(j-i)){
                q = q->next;
            }
        }
        while(p != q && NULL != p && NULL != q){
            p = p->next;
            q = q->next;
        }
        return q;
    }
};

四、142.环形链表II

  1. 第一遍写的

遍历的时候去与array中所有的节点比较,若不同用push_back放进array中,若相同,则就是循环开始点,因为array数组存的是ListNode*的节点,因此相同时一定是循环开始点。时间复杂度O(n),也没有很多,不是很暴力,主要是vector的push_back太好用了,size也是随着变得。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        //还是先思考转数组暴力
        if(NULL == head){
            return NULL;
        }
        vector<ListNode*>array;       
        ListNode *p=head;
        while(NULL != p){
            for(int i=0;i<array.size();i++){
                if(p == array[i]){
                    return p;
                }
            }
            array.push_back(p);
            p = p->next;
        }
        return NULL;
    }
};
  1. 这其实是一道数学题

还是快慢双指针,fast速度为一次两个节点,slow速度为一次一个节点,如果成环,则一定相遇。

相遇后根据计算,从相遇节点起始到循环入口节点与起点到循环入口节点的步数是相等的。于是就能找到了。

class Solution {
public:
 ListNode *detectCycle(ListNode *head) {
     if(nullptr == head || nullptr == head->next){
   return NULL;
 }
        ListNode *fast=head->next->next,*slow=head->next;
        int i=0;   
        while(fast != slow){
            if(nullptr == fast || nullptr == fast->next){
                return nullptr;
            }
            fast = fast->next->next;
            slow = slow->next;
        }
        ListNode *dummyhead = new ListNode(0);
        dummyhead->next = head;
        ListNode *p=head,*q=fast;
        while(p != q){
            p = p->next;
            q = q->next;
        }
        return p;
    }
};

五、总结

链表有很多能直接转到数组里,用vector实现再链表里不方便的操作,我称之为暴力解hh。

对于环形链表的题,主要还是要找到蕴含的关系,之后的代码反而很简单。

(4小时)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值