leetcode 鏈表

實(shí)現(xiàn)一種算法,找出單向鏈表中倒數(shù)第 k 個(gè)節(jié)點(diǎn)。返回該節(jié)點(diǎn)的值。


使用swift語言解決:
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public var val: Int
 *     public var next: ListNode?
 *     public init(_ val: Int) {
 *         self.val = val
 *         self.next = nil
 *     }
 * }
 */
class Solution {
    func kthToLast(_ head: ListNode?, _ k: Int) -> Int {
         var fast = head
// 從1開始到k,那應(yīng)該包括k
         for _ in 1 ... k {
            fast = fast?.next
         }
         var slow = head
         while fast != nil {
              fast = fast?.next
              slow = slow?.next
         }
         return slow?.val ?? 0
    }
}

主要是通過快慢指針快速計(jì)算。快指針先把要倒計(jì)的次數(shù)過掉(1到k,個(gè)數(shù)為k),這樣進(jìn)行指針向后偏移時(shí),偏移次數(shù)就剛好是從正向開始數(shù)到要倒計(jì)的位置(n - k),這樣再結(jié)合一個(gè)全鏈表,讓它跟著快指針偏移,這樣就剛好得到想要的,當(dāng)然最好用筆畫一下更容易理解。
以下的思路是開始的時(shí)候做的:很明顯,時(shí)間復(fù)雜度要高于上面的。

 func kthToLast(_ head: ListNode?, _ k: Int) -> Int {
        var count = 0
        var head1 = head
        if head1 != nil {
            count += 1
        }
        while head1?.next != nil{
               count += 1
            head1 = head1?.next
        }
        if count == 0 {
            return 0
        }

        var tem = 0
        head1 = head
        let index = (count - k)
        while tem != index {
            head1 = head1?.next
            tem += 1
        }
        return head1?.val ?? 0
    }

實(shí)現(xiàn)一種算法,刪除單向鏈表中間的某個(gè)節(jié)點(diǎn)(即不是第一個(gè)或最后一個(gè)節(jié)點(diǎn)),假定你只能訪問該節(jié)點(diǎn)。

解題思路:由于單向鏈表,無法訪問前置節(jié)點(diǎn),所有是無法真實(shí)刪除掉當(dāng)前節(jié)點(diǎn)的,可以采取通過把下一節(jié)點(diǎn)的值賦值給當(dāng)前節(jié)點(diǎn),更新當(dāng)前節(jié)點(diǎn)的值達(dá)到刪除當(dāng)前節(jié)點(diǎn)的值的目標(biāo)。

使用java解決:

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

將兩個(gè)升序鏈表合并為一個(gè)新的 升序 鏈表并返回。新鏈表是通過拼接給定的兩個(gè)鏈表的所有節(jié)點(diǎn)組成的。

解題思路:核心代碼需要指定一個(gè)新鏈表,同時(shí)增加一個(gè)當(dāng)前指針指向鏈表頭,然后當(dāng)前指針為新增節(jié)點(diǎn)不斷后移,表頭指針還在,這樣就可以獲取到整個(gè)鏈表的數(shù)據(jù)元素。

// 鏈表 頭指針
let node =  ListNode(0)
// 當(dāng)前指針
var cur = node
// 新增節(jié)點(diǎn)
let node1 =  ListNode(1)
// 鏈表的下一個(gè)節(jié)點(diǎn)指定是新增節(jié)點(diǎn)
cur.next = node1
// 當(dāng)前指針更新為指向新增節(jié)點(diǎn)
cur = cur.next

具體解決:

func mergeTwoLists(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
        var l11 = l1
        var l22 = l2
        let node =  ListNode(0)
        var cur = node
        while  l11 !=
         nil && l22 != nil {
            if let v1 = l11?.val, let v2 = l22?.val {
                if v1 > v2 {
                    cur.next = l22
                    cur = cur.next ?? ListNode(0)
                    l22 = l22?.next
                }else {
                    cur.next = l11
                    cur = cur.next ?? ListNode(0)
                    l11 = l11?.next
                }
            }
        }
        
        if l11 == nil {
            cur.next = l22
        }else {
            cur.next = l11
        }
        return node.next
    }

注意:鏈表倒置鏈表核心代碼,

        var pre:ListNode? = nil
        while fast != nil{
            let temp = pre
            // 這里相當(dāng)于新創(chuàng)建一個(gè)節(jié)點(diǎn),如果用head節(jié)點(diǎn)賦值,會讓p的next有指向。
            pre = ListNode(head?.val ?? 0)
            // 頭插法 反轉(zhuǎn)
            pre?.next = temp
            fast = fast?.next
        }

真正的倒置應(yīng)該是把當(dāng)前節(jié)點(diǎn)指針改成指向前面節(jié)點(diǎn)。只是通過指針的變化,不新增節(jié)點(diǎn),是最好的,改變原鏈表是必須的。

        var head1 = head;
        var nhead: ListNode? = nil;
        while head1 != nil {
// 臨時(shí)存儲,不需要全局存儲,一個(gè)循環(huán)就重新賦值
           let ntemp = nhead;
// 把原鏈表當(dāng)前要處理的節(jié)點(diǎn)賦給新鏈表的頭節(jié)點(diǎn),也就是原鏈表當(dāng)前要處理的節(jié)點(diǎn)多了一個(gè)新鏈表的頭指針指向它。
            nhead = head1
//接著把原鏈表的當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)用原節(jié)點(diǎn)頭指針緩存,因?yàn)橄乱徊綍淖儺?dāng)前節(jié)點(diǎn)的下一節(jié)點(diǎn)的內(nèi)容為前一節(jié)點(diǎn),防止下一個(gè)節(jié)點(diǎn)找不到,自然需要緩存,用頭節(jié)點(diǎn)即可,無需臨時(shí)指針。
            head1 = head1?.next;
 //頭插法,把當(dāng)前節(jié)點(diǎn)的下節(jié)點(diǎn)指向新鏈表緩存的最新節(jié)點(diǎn)。這樣就完成了倒置(反轉(zhuǎn))鏈表
            nhead?.next =  ntemp;
           
        }

請判斷一個(gè)鏈表是否為回文鏈表。
兩種解法;

  1. 采取棧來處理
int count = 0;
if (head == null) {
            return true;
        }
        ListNode temp = head;
        while (temp != null) {
            count ++;
            temp = temp.next;
        }
        Stack<Integer> stack = new Stack();
        temp = head;
        int i = 0;
        boolean flag = true;
        for (i = 0; i < count /2; i++) {
            stack.push(Integer.valueOf(temp.val));
            temp = temp.next;
        }

        if (count% 2 != 0 ) {
            temp = temp.next;
        }

        ListNode temp1 = temp;
        while (!stack.empty()) {
             Integer tww =  stack.pop();
            try {
                if (temp.val != tww) {
                    flag = false;
                    break;
                }else {
                    temp = temp.next;
                }
            }catch (NullPointerException e) {
                flag = false;
                break;
            }
        }
        return flag;

利用快慢指針處理,快指針向后兩位移動,慢指針按正常一個(gè)一個(gè)移動。遍歷快指針就可以根據(jù)慢指針取得中間位置。遍歷過程中如果加上一個(gè)指針p把前半鏈表值倒置,那最后就只需要遍歷慢指針,就可以比較p和慢指針節(jié)點(diǎn)的值判斷。

func isPalindrome(_ head: ListNode?) -> Bool {
        if head == nil {
            return true
        }
        var fast = head
        var slow = head
        // 用來存儲前半部分反轉(zhuǎn)鏈表的指針
        var p:ListNode? = nil
        while fast != nil && fast?.next != nil {
            fast = fast?.next?.next
            let temp = p
            p = slow
            slow = slow?.next
            // 頭插法 反轉(zhuǎn)
            p?.next = temp
        }
        
        while fast != nil {
            let temp = p
            p = slow
            p?.next = temp
        }
        var flag = true
        while p != nil {
            if p?.val != slow?.val {
                flag = false
                break
            }
            slow = slow?.next
        }
        return flag
    }

劍指 Offer 52. 兩個(gè)鏈表的第一個(gè)公共節(jié)點(diǎn)

問題思路需要捋一下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容