鏈表

1.合并兩個(gè)排序的鏈表:迭代
輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    ListNode dummy=new ListNode(0);     // 弄一個(gè)頭節(jié)點(diǎn)
    ListNode r=dummy;                   // 記錄頭節(jié)點(diǎn)巢寡,最后返回的時(shí)候使用
    while(l1!=null&&l2!=null){
        if(l1.val<=l2.val){
            r.next=l1;
            l1=l1.next;
        } else{
            r.next=l2;
            l2=l2.next;

        }
        r=r.next;
    }
    r.next=l1==null?l2:l1;
    return dummy.next;
}

2.反轉(zhuǎn)鏈表:遞歸

直接用遞歸方法,不然很麻煩僚纷;遞歸都有一個(gè)base闷盔,就是終止條件

1->2->3->4
// 反轉(zhuǎn)得到p
     p
1->2<-3<-4
 <-
把p的節(jié)點(diǎn)指向head潜的,然后把head釋放掉

// 遞歸,時(shí)間空間都是o(n)
public ListNode reverseList(ListNode head) {
    if(head==null||head.next==null){
        return head;
    }
    ListNode p=reverseList(head.next);
    head.next.next=head;
    head.next=null;
    return p;
}

// 非遞歸,時(shí)間o(n),空間o(1)
ListNode* reverseList(ListNode* head) {
        ListNode *pre=NULL;
        ListNode *next=NULL;
        if(head==NULL) return NULL;
        while(head->next){
        next=head->next;
        head->next=pre;
        pre=head;
        head=next;
        }
        head->next=pre;
        return head;
    }

3.反轉(zhuǎn)從位置 m 到 n 的鏈表:遞歸

// 迭代
// 1->2->3->4->5->6. m=2, n=5
// 1->3->2->4->5->6
// 1->4->3->2->5->6
// 1->5->4->3->2->6
      ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode* dummpy = new ListNode(-1);
        dummpy->next = head;
        ListNode* pre = dummpy;
        for (int i = 0; i < m - 1; i++) {
            pre = pre->next;
        }
        ListNode* cur = pre->next;
        for (int i = m; i < n; i++) {
            ListNode* next = cur->next;
            cur->next = next->next;
            next->next = pre->next;
            pre->next = next;
        }
        return dummpy->next;
    }


//*************遞歸************
public ListNode reverseBetween(ListNode head, int m, int n) {
    if(m==1){//從第一個(gè)位置開(kāi)始谨敛,即返回前n個(gè)
        return reverseList(head,n);
    }
    head.next=reverseBetween(head.next,m-1,n-1);
    return head;
}

private ListNode successor;

//反轉(zhuǎn)前n個(gè)元素
public ListNode reverseList(ListNode head, int n) {
    if(n==1){
        successor=head.next;//記錄后繼結(jié)點(diǎn)
        return head;
    }
    ListNode p=reverseList(head.next,n-1);
    head.next.next=head;
    head.next=successor;//將head指向后繼跨嘉,反轉(zhuǎn)整條鏈表尾null
    return p;
}

4.K個(gè)一組反轉(zhuǎn)鏈表:迭代
k 是一個(gè)正整數(shù)尊蚁,它的值小于或等于鏈表的長(zhǎng)度亡笑。
如果節(jié)點(diǎn)總數(shù)不是 k 的整數(shù)倍,那么請(qǐng)將最后剩余的節(jié)點(diǎn)保持原有順序横朋。
示例:
給你這個(gè)鏈表:1->2->3->4->5
當(dāng) k = 2 時(shí)邦蜜,應(yīng)當(dāng)返回: 2->1->4->3->5
當(dāng) k = 3 時(shí)翁逞,應(yīng)當(dāng)返回: 3->2->1->4->5

// *************第一種**********
ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode *dummy = new ListNode(-1), *pre = dummy, *cur = pre;
        dummy->next = head;
        int num = 0;
        while (cur = cur->next) ++num;
        while (num >= k) {
            cur = pre->next;
            for (int i = 1; i < k; ++i) {
                ListNode *next = cur->next;
                cur->next = next->next;
                next->next = pre->next;
                pre->next = next;
            }
            pre = cur;
            num -= k;
        }
        return dummy->next;
    }



// 翻轉(zhuǎn)一個(gè)子鏈表,并且用head迭代,當(dāng)head到尾部時(shí)缚俏,翻轉(zhuǎn)結(jié)束

class Solution {
public:
    // 翻轉(zhuǎn)一個(gè)子鏈表,并且返回新的頭與尾
    pair<ListNode*, ListNode*> myReverse(ListNode* head, ListNode* tail) {
        ListNode* prev = tail->next;
        ListNode* p = head;
        while (prev != tail) {
            ListNode* nex = p->next;
            p->next = prev;
            prev = p;
            p = nex;
        }
        return {tail, head};
    }
     head
// 0->1->2->3->4->5
  hair  tail 
  pre
// 找到第一個(gè)翻轉(zhuǎn)的tail節(jié)點(diǎn)菱父,翻轉(zhuǎn)head力崇,tail節(jié)點(diǎn),得到

    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode* hair = new ListNode(0);
        hair->next = head;
        ListNode* pre = hair;

        while (head) {
            ListNode* tail = pre;
            // 查看剩余部分長(zhǎng)度是否大于等于 k古瓤,找到頭尾鏈表止剖,然后翻轉(zhuǎn)
            for (int i = 0; i < k; ++i) {
                tail = tail->next;
                if (!tail) {
                    return hair->next;
                }
            }
            ListNode* nex = tail->next;
            // 這里是 C++17 的寫(xiě)法,也可以寫(xiě)成
            // pair<ListNode*, ListNode*> result = myReverse(head, tail);
            // head = result.first;
            // tail = result.second;
            tie(head, tail) = myReverse(head, tail);
            // 把子鏈表重新接回原鏈表
            pre->next = head;
            tail->next = nex;
            pre = tail;
            head = tail->next;
        }

        return hair->next;
    }
};

  1. 兩兩反轉(zhuǎn)鏈
// 迭代
ListNode* swapPairs(ListNode* head) {
    ListNode* dummy = new ListNode(0);
    dummy->next = head;
    ListNode* p = head;
    ListNode* pre = dummy;
    while (p != NULL && p->next != NULL) {
        ListNode* cur = p->next;
        ListNode* next = cur->next;
        cur->next = p;
        pre->next = cur;
        pre = p;
        p->next = next;
        p = next;
    }
    return dummy->next;
}



// 遞歸
public ListNode swapPairs(ListNode head) {
    if (head == null || head.next == null) {
        return head;
    }
    ListNode nextHead = swapPairs(head.next.next);
    ListNode next = head.next;
    next.next = head;
    head.next = nextHead;
    return next;
}

6.旋轉(zhuǎn)鏈表
給你一個(gè)鏈表的頭節(jié)點(diǎn) head 落君,旋轉(zhuǎn)鏈表穿香,將鏈表每個(gè)節(jié)點(diǎn)向右移動(dòng) k 個(gè)位置。
輸入:head = [1,2,3,4,5], k = 2
輸出:[4,5,1,2,3]

ListNode* rotateRight(ListNode* head, int k) {
        if (head == NULL || k == 0) return head;
        ListNode* slow = head;
        ListNode* fast = head;
        ListNode* p = head;
        int size = 1;
        while (p->next != NULL) {
            p = p->next;
            size++;
        }
        k = k%size;
        if (k == 0) return head;
        while (k > 0 && fast->next != NULL) {
            fast = fast->next;
            k--;
        }
        while (fast->next != NULL) {
            fast = fast->next;
            slow = slow->next;
        }
        ListNode* newhead = slow->next;
        fast->next = head;
        slow->next = NULL;
        return newhead;
    }

7.分隔鏈表
給你一個(gè)鏈表的頭節(jié)點(diǎn) head 和一個(gè)特定值 x 绎速,請(qǐng)你對(duì)鏈表進(jìn)行分隔皮获,使得所有 小于 x 的節(jié)點(diǎn)都出現(xiàn)在 大于或等于 x 的節(jié)點(diǎn)之前。你應(yīng)當(dāng) 保留 兩個(gè)分區(qū)中每個(gè)節(jié)點(diǎn)的初始相對(duì)位置纹冤。
輸入:head = [1,4,3,2,5,2], x = 3
輸出:[1,2,2,4,3,5]

    ListNode *partition(ListNode *head, int x) {
        ListNode *dummy = new ListNode(-1);
        dummy->next = head;
        ListNode *pre = dummy, *cur = head;
        // 找到值大于x的停止
        while (pre->next && pre->next->val < x) pre = pre->next;
        cur = pre;
        // 
        while (cur->next) {
            if (cur->next->val < x) {
                ListNode *tmp = cur->next;
                cur->next = tmp->next;
                tmp->next = pre->next;
                pre->next = tmp;
                pre = pre->next;
            } else {
                cur = cur->next;
            }
        }
        return dummy->next;
    }

8.復(fù)制帶隨機(jī)指針的鏈表
時(shí)間復(fù)雜度:O(n)洒宝,其中 n 是鏈表的長(zhǎng)度。我們只需要遍歷該鏈表三次萌京。
空間復(fù)雜度:O(1)雁歌。注意返回值不計(jì)入空間復(fù)雜度。
第一種方法:
建立哈希表知残,然后遍歷鏈表靠瞎,深復(fù)制的同時(shí)將復(fù)制的舊節(jié)點(diǎn)作為key,新節(jié)點(diǎn)作為value存進(jìn)哈希表求妹,
第二次遍歷 以原鏈表的一個(gè)節(jié)點(diǎn)的隨機(jī)指針值作為索引乏盐,查找對(duì)應(yīng)的新鏈表的對(duì)應(yīng)節(jié)點(diǎn)的隨機(jī)指針值
第二種方法:將新老鏈表相互間隔的串為一個(gè)鏈表;然后制恍,處理random指針域父能;最后,將老新鏈表拆開(kāi)净神,并返回對(duì)應(yīng)的鏈表頭結(jié)點(diǎn)何吝。

    Node* copyRandomList(Node* head) {
        if (head == nullptr) {
            return nullptr;
        }
        // 1溉委、將新老結(jié)點(diǎn)串為一個(gè)鏈表
        for (Node* node = head; node != nullptr; node = node->next->next) {
            Node* nodeNew = new Node(node->val);
            nodeNew->next = node->next;
            node->next = nodeNew;
        }
        //2、處理random指針域
        for (Node* node = head; node != nullptr; node = node->next->next) {
            Node* nodeNew = node->next;
            nodeNew->random = (node->random != nullptr) ? node->random->next : nullptr;
        }
        //3岔霸、將老新鏈表拆開(kāi)薛躬,返回新鏈表
        Node* headNew = head->next;
        for (Node* node = head; node != nullptr; node = node->next) {
            Node* nodeNew = node->next;
            node->next = node->next->next;
            nodeNew->next = (nodeNew->next != nullptr) ? nodeNew->next->next : nullptr;
        }
        return headNew;
    }

9.刪除鏈表重復(fù)元素

******************第一種,重復(fù)一個(gè)不留*****************
輸入:head = [1,2,3,3,4,4,5] 
輸出:[1,2,5]

ListNode* deleteDuplicates(ListNode* head) {
        if (head == NULL) return NULL;
        ListNode* pre = new ListNode();
        pre->next = head;
        ListNode* newhead = pre;
        ListNode* cur = head;
        while (cur->next!= NULL) {
            if(cur->val == cur->next->val) {
                while (cur->next != NULL && cur->val == cur->next->val)
                    cur = cur->next;
                if (cur->next == NULL) {
                    pre->next = NULL;
                    break;
                }
                pre->next = cur->next;
                cur = cur->next;
            } else {
                cur = cur->next;
                pre = pre->next;
            }
        }
    return newhead->next;
    }
    
********************第二種呆细,重復(fù)留一個(gè)******************
輸入:head = [1,2,3,3,4,4,5] 
輸出:[1,2,3,4,5]

    ListNode* deleteDuplicates(ListNode* head) {
        if (head == NULL) return head;
        ListNode* pre = new ListNode();
        pre->next = head;
        ListNode* cur = head;
        ListNode* point = pre;
        while (cur->next != NULL) {
            while (cur->next != NULL && cur->next->val == cur->val) cur = cur->next;
            pre->next = cur;
            if (cur->next == NULL) {
                break;
            }
            cur = cur->next;
            pre = pre->next;
        }
        return point->next;
    }

10.合并k個(gè)鏈表:遞歸


image.png
  
# 最簡(jiǎn)單的方法
ListNode* mergeKLists(vector<ListNode*>& lists) {
        if (lists.size()==0) return NULL;
        for(int i = 1; i < lists.size(); i++) {
            lists[i] = mergeTwoLists(lists[i-1],lists[i]);
        }
        return lists[lists.size()-1];
    }

    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if (l1 == NULL && l2 == NULL) return NULL;
        if (l1 == NULL) return l2;
        if (l2 == NULL) return l1;
        ListNode* merged;
        if (l1->val > l2->val) {
            merged = l2;
            l2 = l2->next;
            merged->next= mergeTwoLists(l1,l2);
        } else {
            merged = l1;
            l1 = l1->next;
            merged->next = mergeTwoLists(l1,l2);
        }
        return merged;
    }


#  分治合并型宝,每次把list分成2個(gè)
class Solution {
        public ListNode mergeKLists(ListNode[] lists) {
            return merger(lists, 0, lists.length - 1);
        }

        private ListNode merger(ListNode[] lists, int l, int r) {
            if (l == r) {
                return lists[l];
            }
            if (l > r) {
                return null;
            }
            //右移一位相當(dāng)于除2
            int mid=(l+r)>>1;

            return mergeTwoLists(merger(lists,l,mid),merger(lists,mid+1,r));
        }


        public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
            ListNode pre = new ListNode(0);
            ListNode curr = pre;
            while (l1 != null || l2 != null) {
                if (l1 == null) {
                    curr.next = l2;
                    return pre.next;
                }

                if (l2 == null) {
                    curr.next = l1;
                    return pre.next;
                }

                if (l1.val < l2.val) {
                    curr.next = l1;
                    curr = curr.next;
                    l1 = l1.next;
                } else {
                    curr.next = l2;
                    curr = curr.next;
                    l2 = l2.next;
                }
            }

            return pre.next;
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市絮爷,隨后出現(xiàn)的幾起案子趴酣,更是在濱河造成了極大的恐慌,老刑警劉巖坑夯,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岖寞,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡柜蜈,警方通過(guò)查閱死者的電腦和手機(jī)仗谆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)淑履,“玉大人隶垮,你說(shuō)我怎么就攤上這事∶卦耄” “怎么了狸吞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)指煎。 經(jīng)常有香客問(wèn)我蹋偏,道長(zhǎng),這世上最難降的妖魔是什么至壤? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任威始,我火速辦了婚禮,結(jié)果婚禮上像街,老公的妹妹穿的比我還像新娘字逗。我一直安慰自己,他們只是感情好宅广,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著些举,像睡著了一般跟狱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上户魏,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天驶臊,我揣著相機(jī)與錄音挪挤,去河邊找鬼。 笑死关翎,一個(gè)胖子當(dāng)著我的面吹牛扛门,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播纵寝,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼论寨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了爽茴?” 一聲冷哼從身側(cè)響起葬凳,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎室奏,沒(méi)想到半個(gè)月后火焰,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胧沫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年昌简,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绒怨。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纯赎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窖逗,到底是詐尸還是另有隱情址否,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布碎紊,位于F島的核電站佑附,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏仗考。R本人自食惡果不足惜音同,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秃嗜。 院中可真熱鬧权均,春花似錦、人聲如沸锅锨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)必搞。三九已至必指,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間恕洲,已是汗流浹背塔橡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工梅割, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人葛家。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓户辞,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親癞谒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子底燎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 合并兩個(gè)排序的鏈表[https://leetcode-cn.com/problems/he-bing-liang-...
    wyof閱讀 161評(píng)論 0 1
  • 一、反轉(zhuǎn)問(wèn)題 2021.02.11 No.25 K個(gè)一組翻轉(zhuǎn)鏈表 給你一個(gè)鏈表扯俱,每 k 個(gè)節(jié)點(diǎn)一組進(jìn)行翻轉(zhuǎn)书蚪,請(qǐng)你返...
    維李設(shè)論閱讀 597評(píng)論 0 0
  • LeetCode-鏈表 鏈表(Linked List)是一種常見(jiàn)的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),是一種線(xiàn)性表迅栅,但是并不會(huì)按線(xiàn)性的順...
    raincoffee閱讀 1,202評(píng)論 0 6
  • 題目匯總https://leetcode-cn.com/tag/linked-list/92. 反轉(zhuǎn)鏈表 II中等...
    今天柚稚了么閱讀 231評(píng)論 0 0
  • 刪除鏈表的倒數(shù)第N個(gè)節(jié)點(diǎn) 給定一個(gè)鏈表殊校,刪除鏈表的倒數(shù)第 n 個(gè)節(jié)點(diǎn),并且返回鏈表的頭結(jié)點(diǎn)读存。 示例:給定一個(gè)鏈表:...
    我是小曼巴閱讀 325評(píng)論 0 0