力扣高頻|算法面試題彙總(五):鏈表

力扣高頻|算法面試題彙總(五):鏈表

力扣鏈接
目錄:

  • 1.複製帶隨機指針的鏈表
  • 2.環形鏈表
  • 3.排序鏈表
  • 4.相交鏈表
  • 5.反轉鏈表
  • 6.迴文鏈表
  • 7.刪除鏈表中的節點
  • 8.奇偶鏈表

1.複製帶隨機指針的鏈表

給定一個鏈表,每個節點包含一個額外增加的隨機指針,該指針可以指向鏈表中的任何節點或空節點。
要求返回這個鏈表的 深拷貝。
我們用一個由 n 個節點組成的鏈表來表示輸入/輸出中的鏈表。每個節點用一個 [val, random_index] 表示:
val:一個表示 Node.val 的整數。
random_index:隨機指針指向的節點索引(範圍從 0 到 n-1);如果不指向任何節點,則爲 null 。

示例1:
在這裏插入圖片描述

輸入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
輸出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

思路1:
回溯法。參考力扣官方
在這裏插入圖片描述
回溯算法的第一想法是將鏈表想象成一張圖。鏈表中每個節點都有 2 個指針(next和random)。隨機指針給圖結構添加了隨機性,所以我們可能會訪問相同的節點多次,這樣就形成了環。只需要遍歷整個圖並拷貝它。爲例避免這種情況,需要用用一個字典記錄是否遍歷節點。步驟如下

  • 1.從頭指針開始遍歷整個圖。
  • 2.當遍歷到某個節點時判斷是否經過這個節點,如果已經經過該節點則不需要拷貝。
  • 3.如果沒有經過這個節點,則進行拷貝。
  • 4.分佈對nextrandom指針進行回溯調用。
    時間複雜度:O(N)O(N) ,其中 N 是鏈表中節點的數目。空間複雜度:O(N)O(N)

C++

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
private:
    // 字典將舊節點作爲鍵,新節點作爲其值
    map<Node*, Node*> nodeHash;
public:
    Node* copyRandomList(Node* head) {
        if(!head)
            return head;
        // 回溯法先判斷是否已經遍歷
        // 如果我們已經處理了當前節點,那麼我們只需返回它的克隆版本
        if(nodeHash.find(head) != nodeHash.end())
            return nodeHash[head];
        // 創建新的節點 值與舊節點相同
        Node* node = new Node(head->val);;
        // 添加到字典中
        // 將此值保存在哈希圖中。 這是必需的,
        // 因爲遍歷過程中由於隨機指針的隨機性可能會出現循環,這將有助於我們避免循環。
        nodeHash[head] = node;
        // 遞歸尋找
        // 以遞歸方式複製剩餘的鏈表,從下一個指針開始,然後從隨機指針開始。
        // 因此,我們有兩個獨立的遞歸調用。
        // 最後,我們爲創建的新節點更新下一個和隨機指針。
        node->next = copyRandomList(head->next);
        node->random = copyRandomList(head->random);
        
        return node;
    }
};/**/

Python

"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""

class Solution:
    # 初始化節點字典
    def __init__(self):
        self.nodeHash = {}
    def copyRandomList(self, head: 'Node') -> 'Node':     
        if head == None:
            return head
        # 回溯的截止條件
        if head in self.nodeHash:
            return self.nodeHash[head]
        # 拷貝節點
        node =  Node(head.val)
        self.nodeHash[head] = node  
        node.next = self.copyRandomList(head.next)
        node.random = self.copyRandomList(head.random)    
        return node       

思路2:
O(1)O(1)空間的迭代。參考力扣官方
在這裏插入圖片描述
這個方法和劍指offer|解析和答案(C++/Python) (三):複雜鏈表的複製基本類似。算法分爲三個步驟:

  • 1.複製鏈表,即擴充原鏈表。
  • 2.複製鏈表上鍊接隨機節點。
  • 3.複製鏈表和原鏈表斷開,得到複製鏈表。

C++

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/
class Solution {
public:
    Node* copyRandomList(Node* head) {
        // 複製原鏈表節點
        cloneNodes(head);
        // 複製隨機節點
        cloneRandomNodes(head);
        // 斷開復制鏈表
        return reconnectNodes(head);
    }
    void cloneNodes(Node* head){
        Node* pNode = head;
        while(pNode){
            // 拷貝節點
            Node* node = new Node(pNode->val);
            node->next = pNode->next;
            pNode->next = node;
            // 移位
            pNode = node->next;
        }
    }
    void cloneRandomNodes(Node* head){
        Node* pNode = head;
        while(pNode){
            // 隨機節點鏈接
            Node* node = pNode->next;
            if(pNode->random){// 如果原節點的隨機鏈接不爲空
                node->random = pNode->random->next;
            }
            // 移位
            pNode = node->next;
        }
    }
    Node* reconnectNodes(Node* head){
        Node* pCloneHead = NULL;
        Node* pCloneNode = NULL;
        Node* pNode = head;
        // 獲得原鏈表和複製鏈表的頭指針
        if(pNode){
            pCloneHead = pNode->next;
            pCloneNode = pCloneHead;
            // 斷開鏈接
            pNode->next = pCloneNode->next;
            // 移位
            pNode = pNode->next;
        }
        // 拆開
        while(pNode){
            pCloneNode->next = pNode->next;
            pCloneNode = pCloneNode->next;
            // 斷開鏈接
            pNode->next = pCloneNode->next;
            // 移位
            pNode = pNode->next;
        }
        return pCloneHead;
    }
};

Python:

"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        self.cloneNodes(head)
        self.cloneRandomNodes(head)
        return self.reconnectNodes(head)
    def cloneNodes(self, head):
        pNode = head
        while pNode:
            # 拷貝
            node = Node(pNode.val)
            node.next = pNode.next
            pNode.next = node
            pNode = node.next
    def cloneRandomNodes(self, head):
        pNode = head
        while pNode:
            node = pNode.next
            if pNode.random:
                node.random = pNode.random.next
            pNode = node.next
    def reconnectNodes(self, head):
        pCloneHead = None
        pCloneNode = None
        pNode = head
        # 找頭節點
        if pNode:
            pCloneHead = pNode.next
            pCloneNode = pCloneHead
            # 斷開
            pNode.next = pCloneNode.next
            # 移位
            pNode = pNode.next
        while pNode:
            pCloneNode.next = pNode.next
            pCloneNode = pCloneNode.next
            pNode.next = pCloneNode.next
            pNode = pNode.next
        return pCloneHead

2.環形鏈表

給定一個鏈表,判斷鏈表中是否有環。
爲了表示給定鏈表中的環,我們使用整數 pos 來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。 如果 pos 是 -1,則在該鏈表中沒有環。

示例:

輸入:head = [3,2,0,-4], pos = 1
輸出:true
解釋:鏈表中有一個環,其尾部連接到第二個節點。

在這裏插入圖片描述
思路:
這道題是劍指offer|解析和答案(C++/Python) (二):鏈表中環的入口節點中的簡單版,只需要考慮是否環存在。設置兩個指針,一個快指針,一個慢指針,兩個指針相遇則存在環,否則不存在。
C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        // 兩個指針,一個快指針,一個慢指針
        ListNode* pSlow;
        ListNode* pFast;
        pSlow = head;
        pFast = head;
        while(pFast){
            pSlow = pSlow->next;
            pFast = pFast->next;
            if(pFast)
                pFast = pFast->next;
            else
                return false;
            if(pFast == pSlow)
                return true;
        }
        return false;
    }
};

Python

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        if head == None:
            return False;
        pSlow = head
        pFast = head
        while pFast:
            pSlow = pSlow.next
            pFast = pFast.next
            if pFast:
                pFast = pFast.next
            else:
                return False
            if pFast == pSlow:
                return True
        return False

3.排序鏈表

在 O(n log n) 時間複雜度和常數級空間複雜度下,對鏈表進行排序。
示例 1:
輸入: 4->2->1->3
輸出: 1->2->3->4
示例 2:
輸入: -1->5->3->4->0
輸出: -1->0->3->4->5

思路:
由於需要O(nlogn)O(n log n) 時間複雜度,所以採用歸併排序,由於常熟級空間複雜度,所以不能使用遞歸,得使用循環參考圖示
在這裏插入圖片描述
C++:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
	ListNode* sortList(ListNode* head) {
		if (head == NULL|| head->next ==NULL)
			return head;
		// 獲取鏈表長度
		ListNode* pNode = head;
		int length = 0;
		while (pNode) {
			pNode = pNode->next;
			++length;
		}
		ListNode* pRoot = new ListNode(0);	/*新建根節點*/
		pRoot->next = head;					/*節點鏈接起來*/
		int len = 1;							/*設置每次歸併的長度*/
		while (len <length)
		{
			ListNode* pMerge = pRoot;		/*合併的起始節點*/
			ListNode* pNode = pRoot->next;	/*移動的節點*/
			while (pNode)
			{
				/*構建合併的鏈表h1*/
				ListNode* pH1 = pNode;
				int lH1 = len;
				while (pNode != NULL && lH1 > 0) {
					pNode = pNode->next;
					--lH1;
				}
				if (lH1 > 0)				/*如果h1不是完整長度,則說明沒有h2*/
					break;					/*則無需合併h2*/
				ListNode* pH2 = pNode;
				int lH2 = len;
				while (pNode != NULL && lH2 > 0) {
					pNode = pNode->next;
					--lH2;
				}
				int lenH1 = len;
				int lenH2 = len - lH2;		/*h2可能不是完整長度*/
				while (lenH1 > 0 && lenH2 > 0)/*歸併排序*/
				{	
					/*鏈接子鏈表*/
					if (pH1->val <= pH2->val) {
						pMerge->next = pH1;
						pH1 = pH1->next;
						--lenH1;
					}
					else {
						pMerge->next = pH2;
						pH2 = pH2->next;
						--lenH2;
					}
					pMerge = pMerge->next;	/*移動*/
				}
				if (lenH1 > 0) {			/*h1鏈表還有剩餘*/
					pMerge->next = pH1;
					while (lenH1)
					{
						pMerge = pMerge->next;/*不斷移動pMerge*/
						--lenH1;
					}
				}
				else if (lenH2 > 0) {
					pMerge->next = pH2;
					while (lenH2)
					{
						pMerge = pMerge->next;
						--lenH2;
					}
				}
				pMerge->next = pNode;		/*鏈接後面的部分*/
			}
			len = len * 2;
		}
		return pRoot->next;
	}	
};

Python:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        if not head or head.next == None:
            return head
        # 獲取鏈表的長度
        pNode, length = head, 0
        while pNode:
            pNode, length = pNode.next, length + 1
        # 新建根節點
        pRoot = ListNode(0)
        pRoot.next = head
        l = 1 # 設置每次合併的規模
        # 根據不同的鏈表切片規模,每一次都從頭進行歸併
        while l < length :
            # 合併的第一個節點、移動的節點
            pMerge, pNode = pRoot, pRoot.next
            # 根據當前的合併規模,將鏈表內的鏈表切片兩兩歸併
            while pNode: # 如果節點沒有移動到最後時
                # 獲取當前需要歸併的子鏈表h1
                pH1, lH1 = pNode, l
                # 不斷移動pNode獲得子鏈表
                while lH1 and pNode:
                    pNode, lH1 = pNode.next, lH1 - 1
                if lH1 > 0: # 沒有獲取完整長度的子鏈h1,說明沒有h2,無需合併
                    break
                # 獲取當前需要歸併的子鏈表h2
                pH2, lH2 = pNode, l
                # 不斷移動pNode獲得子鏈表
                while lH2 and pNode:
                    pNode, lH2 = pNode.next, lH2 - 1
                # 獲取h1和h2鏈表的長度
                lenH1, lenH2 = l, l - lH2 # lenH2長度可能比lenH1小
                # 歸併排序
                while lenH1 and lenH2:
                    if pH1.val <= pH2.val:
                        pMerge.next = pH1
                        pH1 = pH1.next
                        lenH1 = lenH1 - 1
                    else:
                        pMerge.next = pH2
                        pH2 = pH2.next
                        lenH2 = lenH2 - 1
                    pMerge = pMerge.next
                # 如果h1有剩餘的
                if lenH1 > 0:
                    pMerge.next = pH1 # 鏈接h1
                    while lenH1:
                        pMerge = pMerge.next # 移動pMerge
                        lenH1 -= 1
                else:# 如果h2有剩餘的
                    pMerge.next = pH2 # 鏈接h2
                    while lenH2:
                        pMerge = pMerge.next # 移動pMerge
                        lenH2 -= 1
                # h1 和 h2 的歸併只是影響了鏈表的一部分,
                # 這裏應該把歸併後的鏈表切片跟原鏈表h2之後的部分拼起來
                pMerge.next = pNode
            # 得到新的合併規模
            l *= 2
        return pRoot.next     

4.相交鏈表

編寫一個程序,找到兩個單鏈表相交的起始節點。

示例1:
在這裏插入圖片描述

輸入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
輸出:Reference of the node with value = 8
輸入解釋:相交節點的值爲 8 (注意,如果兩個鏈表相交則不能爲 0)。從各自的表頭開始算起,鏈表 A 爲 [4,1,8,4,5],鏈表 B 爲 [5,0,1,8,4,5]。在 A 中,相交節點前有 2 個節點;在 B 中,相交節點前有 3 個節點。

思路:
劍指offer有,可以看我以前寫的博客:劍指offer|解析和答案(C++/Python) (四):兩個鏈表的第一個公共節點
首先遍歷兩個鏈表得到兩個鏈表的長度。第二次遍歷的時候,在較長的鏈表上走若干步,接着同時在兩個鏈表上進行遍歷,找到第一個相同的節點便是第一個公共節點。這裏不需要輔助棧,時間複雜度同樣是O(m+n)O(m+n)
C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        // 獲取鏈表A的長度
        int lengthA = 0;
        ListNode * pNode = headA;
        while(pNode){
            pNode = pNode->next;
            ++lengthA;
        }
        // 獲取鏈表B的長度
        int lengthB = 0;
        pNode = headB;
        while(pNode){
            pNode = pNode->next;
            ++lengthB;
        }
        ListNode * pNodeA = headA;
        ListNode * pNodeB = headB;
        int diff = lengthA - lengthB;
        if(diff >= 0){
            // A鏈表長,A先走
            while(diff){
               pNodeA = pNodeA->next;
                --diff;
            }
        }else{
            diff = -diff;
            while(diff){
                pNodeB = pNodeB->next;
                --diff;
            }
        }
        // 一起走找共同節點
        while(pNodeA && pNodeB){
            if(pNodeA == pNodeB){
                return pNodeA;
            }else{
                pNodeA = pNodeA->next;
                pNodeB = pNodeB->next;
            }
        }
        return NULL;
    }
};

Python:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        lengA = 0
        lengB = 0
        pNode = headA
        while pNode:
            pNode = pNode.next
            lengA += 1
        pNode = headB
        while pNode:
            pNode = pNode.next
            lengB += 1
        diff = lengA - lengB
        pNodeA = headA
        pNodeB = headB
        if diff >= 0:
            while diff:
                pNodeA = pNodeA.next
                diff -= 1
        else:
            diff = -diff
            while diff:
                pNodeB = pNodeB.next
                diff -= 1
        while pNodeA and pNodeB:
            if pNodeA == pNodeB:
                return pNodeA
            pNodeA = pNodeA.next
            pNodeB = pNodeB.next
        return None

5.反轉鏈表

反轉一個單鏈表。
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
進階:
你可以迭代或遞歸地反轉鏈表。你能否用兩種方法解決這道題?

思路:
這題在劍指offer做過,詳見劍指offer|解析和答案(C++/Python) (二):反轉鏈表。使用3個指針完成反轉。
C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == NULL or head->next == NULL)
            return head;
        ListNode* pNode = head;
        ListNode* pPre = NULL;
        ListNode* pRever = NULL;
        while(pNode->next){
            pRever = pNode->next;
            pNode->next = pPre;
            pPre = pNode;
            pNode = pRever;
        }
        pRever->next = pPre;
        return pRever;
    }
};

Python:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if head == None or head.next == None:
            return head
        pNode = head
        pPre = None
        pRever = None
        while pNode.next:
            pRever = pNode.next
            pNode.next = pPre
            pPre = pNode
            pNode = pRever
        pRever.next = pPre
        return pRever

思路2:
遞歸。這個有點繞,參考官方
在這裏插入圖片描述
C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == NULL or head->next == NULL)
            return head;
        ListNode* p = reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        return p;
    }
};

Python:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if head == None or head.next == None:
            return head
        pNode = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return pNode

6.迴文鏈表

請判斷一個鏈表是否爲迴文鏈表。
示例 1:
輸入: 1->2
輸出: false
示例 2:
輸入: 1->2->2->1
輸出: true
進階:
你能否用 O(n) 時間複雜度和 O(1) 空間複雜度解決此題?

思路
使用快慢指針和棧實現
空間複雜度O(n/2)O(n/2)

  • 快指針每次走兩步,慢指針每次只走一步。
  • 當快指針走到鏈表末尾時,慢指針剛好走到中間位置,從慢指針後面的鏈表開始壓棧,再出棧依次和鏈表前部分比較。

(1)——>(2)——>(3)——>(2)——>(1)
               slow           fast
(1)——>(2)——>(3)——>(3)——>(2) ——>  (1)
               slow        (fast)  <strong>多走1步</strong> fast

C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if(head == NULL || head->next == NULL)
            return true;
        ListNode* pSlow;
        ListNode* pFast;
        pSlow = head;
        pFast = head;
        while(pFast->next && pFast->next->next){
            pSlow = pSlow->next;
            pFast = pFast->next->next;
        }

        // 將鏈表的後半段壓入棧
        stack<int> s;
        while(pSlow->next){
            s.push(pSlow->next->val);
            pSlow = pSlow->next;
        }
        //依次比較前半部分元素和逆序的後半部分元素
        while(!s.empty()){
            if(s.top() == head->val){
                s.pop();
                head = head->next;
            }else
                return false;
        }
        return true;
    }
};

Python:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        if not head or not head.next:
            return True
        pSlow = head
        pFast = head
        while pFast.next and pFast.next.next:
            pSlow = pSlow.next
            pFast = pFast.next.next
        stack = []
        while pSlow.next:
            stack.append(pSlow.next.val)
            pSlow = pSlow.next
        while len(stack):
            if stack[-1] == head.val:
                head = head.next
                stack.pop()
            else:
                return False
        return True

思路2
進階,使用O(1)O(1)空間複雜度。
和上一個思路的區別在於:最後不使用棧來倒序鏈表後半部分的元素,而是選擇直接本地操作(額外空間複雜度爲O(1)),在原鏈表上將後半部分元素倒置(反轉),比較完後得出結果後,再 還原鏈表,返回結果。
C++

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if(head == NULL || head->next == NULL)
            return true;
        ListNode* pSlow;
        ListNode* pFast;
        pSlow = head;
        pFast = head;
        while(pFast->next && pFast->next->next){
            pSlow = pSlow->next;
            pFast = pFast->next->next;
        }
        //鏈表長度爲偶數,fast指針最後多走一步到鏈表末尾
        if(pFast->next)
            pFast = pFast->next;
        /*---------------區別----------------------*/
        /*---------------鏈表後半部分倒序-----------*/
        ListNode* p = pSlow->next;
        ListNode* q = NULL;
        ListNode* cur = NULL;
        pSlow->next = NULL;
        while(p){
            cur = p->next;
            p->next = q;
            q = p;
            p = cur;
        }
        while(1){
            if(pFast->val != head->val){// 不相等在不是
                // 鏈表復原
                ListNode* m = q->next;
                ListNode* n = NULL;
                ListNode* cur2 = NULL;
                q->next = NULL;
                while(m){
                    cur2 = m->next;
                    m->next = n;
                    n = m;
                    m = cur2;
                }
                pSlow->next = n;
                return false;     
            }
            //前、後一起往後移動
            pFast = pFast->next;
            head = head->next;
            if(pFast == NULL)
                break;
        }
        //鏈表復原
        ListNode* m = q->next;
        ListNode* n = NULL;
        ListNode* cur2 = NULL;
        q->next = NULL;
        while(m){
            cur2 = m->next;
            m->next = n;
            n = m;
            m = cur2;
        }
        pSlow->next = n;
        return true;
    }
};

7.刪除鏈表中的節點

請編寫一個函數,使其可以刪除某個鏈表中給定的(非末尾)節點,你將只被給定要求被刪除的節點。
示例:
輸入: head = [4,5,1,9], node = 5
輸出: [4,1,9]
解釋: 給定你鏈表中值爲 5 的第二個節點,那麼在調用了你的函數之後,該鏈表應變爲 4 -> 1 -> 9.
說明:
鏈表至少包含兩個節點。
鏈表中所有節點的值都是唯一的。
給定的節點爲非末尾節點並且一定是鏈表中的一個有效節點。
不要從你的函數中返回任何結果。

思路
這題和從鏈表中刪除節點有點不一樣,因爲那個會給你頭節點,一直遍歷到要刪除的節點。但是這個直接給你要刪除的節點,不知道前置節點的。思路如圖所示:
在這裏插入圖片描述
複製下一個節點的值,再鏈接下一個節點的下一個節點。
C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void deleteNode(ListNode* node) {
        node->val = node->next->val;
        node->next = node->next->next;
    }
};

Python:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def deleteNode(self, node):
        """
        :type node: ListNode
        :rtype: void Do not return anything, modify node in-place instead.
        """
        node.val = node.next.val
        node.next = node.next.next

8.奇偶鏈表

給定一個單鏈表,把所有的奇數節點和偶數節點分別排在一起。請注意,這裏的奇數節點和偶數節點指的是節點編號的奇偶性,而不是節點的值的奇偶性。
請嘗試使用原地算法完成。你的算法的空間複雜度應爲 O(1),時間複雜度應爲 O(nodes),nodes 爲節點總數。
示例 1:
輸入: 1->2->3->4->5->NULL
輸出: 1->3->5->2->4->NULL
說明:
應當保持奇數節點和偶數節點的相對順序。
鏈表的第一個節點視爲奇數節點,第二個節點視爲偶數節點,以此類推。

思路
使用兩個指針,分別用來鏈接奇數節點和偶數節點。在鏈接完之後,這個鏈表被拆分程兩個部分:奇數節點子鏈表和偶數節點子鏈表,因此最後一步就是把兩個鏈表鏈接起來。
C++

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        if(head == NULL || head->next==NULL)
            return head;
        ListNode* pOdd = head;
        ListNode* pEven = head->next;
        ListNode* pEvenHead = pEven;
        while(pOdd->next && pEven->next){
            // 鏈接
            pOdd->next = pEven->next;
            // 移位
            pOdd = pOdd->next;
            pEven->next = pOdd->next;
            pEven = pEven->next;
        }
        // 鏈接奇偶鏈
        pOdd->next = pEvenHead;
        return head;
    }
};

Python

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head
        pOdd = head
        pEven = head.next
        pEvenHead = pEven
        while pOdd.next and pEven.next:
            pOdd.next = pEven.next
            pOdd = pOdd.next
            pEven.next = pOdd.next
            pEven = pEven.next
        pOdd.next = pEvenHead
        return head
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章