LeetCode 160, 139, 41 題解

LeetCode 160, 139, 41 題解

如下的表達純屬我的理解,若是有不對,歡迎指出 : )。node

題解

(LeetCode 160)Intersection of Two Linked Lists

題目:

Write a program to find the node at which the intersection of two singly linked lists begins.數組

For example, the following two linked lists:spa

A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3

begin to intersect at node c1.指針

Notes:code

  • If the two linked lists have no intersection at all, return null.內存

  • The linked lists must retain their original structure after the function returns.leetcode

  • You may assume there are no cycles anywhere in the entire linked structure.字符串

  • Your code should preferably run in O(n) time and use only O(1) memory.get

大意就是給了兩個鏈表,而後這兩個鏈表的後面有一個段公共部分,讓你找到這段公共部分的開始節點。數據保證鏈表裏面沒有環。若是兩個鏈表沒有公共部分,就返回空。要求在尋找的過程當中,必須保持兩個鏈表的原始結構,同時時間和空間複雜度要求爲 O(n) 和 O(1)。同步

題解

其實在不少狀況下,實現 O(n) 複雜度的方式,就是多走幾遍,只要這個幾是常數就能夠了。

在這道題裏面,因爲鏈表都是單鏈表,因此只能一直日後走,不能往前走。同時在一個節點上的時候,不能知道這個鏈表後面的狀況(好比說元素的個數)。

對於像這樣的鏈表(或者說是節點指針結構)找公共節點的題,要找公共節點,比較直接能想到的是:若是兩個指針自己是上下對齊的(就是說距離公共節點的距離),只要兩個指針一塊兒往前走,就確定會走到同一個節點。

但是如今兩個指針是不對齊的,怎麼辦呢?就讓他對齊唄。

按照前面說的多走幾遍的套路,看看走一次能獲得什麼:鏈表的長度。觀察鏈表:後邊的公共部分的長度是相同的,因此長度的差別就在前面,那咱們只要把兩個鏈表的長度差 distance 算出來,讓指向長鏈表的指針提早走 distance 步,就能夠了同步走了。

function get_insersection_node(headA, headB)
    distance <- get_length_diff(headA, headB)
    longer_pointer <- get_longer_link_head(headA, headB)
    shorter_pointer <- get_short_link_head(headA, headB)
    move_pointer(longer_poiner, distance)
    
    while (longer_pointer != nil) and (shorter_pointer != nil)
        if (longer_pointer = short_pointer) then
            return longer_pointer
        longer_pointer <- longer_pointer.next
        shorter_pointer <- shorter_pointer.next
        
    // 跑到這裏說明兩個鏈表並無公共部分
    return nil

相似的題

給定一個二叉樹,每一個節點都有指向他老爸的指針。再給任意兩個節點,找到他們的最年輕的公共祖先。

這個題,其實能夠用和同上面的題相同的思路解決 : )

(LeetCode 139) Word Break

題目

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words. You may assume the dictionary does not contain duplicate words.

For example, given
s = "leetcode",
dict = ["leet", "code"].

Return true because "leetcode" can be segmented as "leet code".

大意就是給定一個字符串和一個單詞列表,判斷這個字符串是否是能夠徹底由單詞列表的單詞組成。題目保證單詞列表裏面不會有重複的單詞

題解

定義 s[m..n] (m <= n)表示 字符串從第 m 個到第 n 個字符組成的子串。

設 s 的長度爲n

觀察這個問題,其實這個問題是能夠拆分紅不少徹底相同的字問題的。對於這個問題的定義能夠表述成:判斷 s[1..n] 能不能徹底由單詞列表裏面的單詞組成。

那麼,他的子問題(規模較小的問題) 就是: s[1..1], s[1..2], s[1..3], … s[1..n - 1] 能不能徹底由單詞列表裏面的單詞組成。

假設存在一個j(1 <= j < n),使得 s[1..j] 是能夠徹底由單詞列表的單詞組成的,同時 s[j + 1 .. n] 這個單詞又在字典列表裏面,那麼就說明 s[1..n] 是能夠徹底由單詞列表裏面的單詞構成的。

也就是說,要解決 s[1..n] 的問題,咱們解決了 s[1..1], s[1..2], s[1..3], … s[1..n-1] 這些子問題(由於若是不所有解決的話,就不知道是否存在這麼一個 j )。反過來講,只要解決 s[1..1], s[1..2], s[1..3], … s[1..n-1] 這些子問題,咱們就能解決 s[1..n] 的問題。

在解決這個問題的過程當中,s[1..n] 問題所處的階段就叫當前階段,對於當前階段而言,s[1..1], s[1..2], s[1..3], … s[1..n-1] 問題所處的階段就是上一階段

s[1..n] 可否徹底由單詞列表裏的單詞組成,就是當前階段的狀態,s[1..1], s[1..2], s[1..3], … s[1..n-1]可否徹底由單詞列表裏面的單詞組成,就是上一階段的狀態

好,如今來觀察一下上面的分析,就能發現 對於一個 s[1..n] 問題,有可能,從上一階段的幾個狀態都能到達當前的狀態。也就是說:單詞的選擇方式不必定是惟一的。可是,在解決 s[1..n] 的時候,並不須要關心 s[1..1],s[1..2],..,s[1..n -1] 問題的解是怎麼來的。這就是無後效性

當一個判斷性的問題,具備這種子問題性質和無後效性的性質,就能夠考慮採用動態規劃的方式去作。

狀態咱們已經定義好了,那麼用狀態變量 is_beakable[i] 來表示 "s[1..n] 可否徹底由單詞列表裏的單詞組成" 這個狀態。true 表示能夠,false 表示不能夠。

從各個 s[1..j] 到 s[1..n] 就稱爲狀態轉移,這裏的狀態轉移鏈接了當前階段和上一階段。咱們能夠考慮用狀態轉移方程來描述(is_breakable[i] 默認值爲 false):

is_breakable[i] = is_breakable[i] Or ((is_breakable[j] = true) And (s[j + 1..n] in dict))

就這樣,咱們一直算出 is_breakable[n] 就算是將問題求解完了。

function word_break(s, dict)
    is_breakable[0] = false;
    for i <- 1 to n do 
        is_breakable[i] = false;
        for j <- 0 to n do
            is_breakable[i] = is_breakable[i] or ((is_breakable[j] = true) and (s[j + 1..n] in dict))
    return is_breakable[n]

(LeetCode 41) First Missing Positive

題目

Given an unsorted integer array, find the first missing positive integer.

For example,
Given [1,2,0] return 3,
and [3,4,-1,1] return 2.

Your algorithm should run in O(n) time and uses constant space.

大意就是,給定一個沒有排過序的數組,裏面的數有負有正。正整數序列是:1, 2, 3,… 找到第一個丟失的正整數。要求時間複雜度和空間複雜度是O(n)和O(1)。

題解

這個題,並無不改變原數組就能在O(n)的空間效率內實現的方法,因此只能考慮改變原有的內存。

觀察這個題,知道:

  1. 目標數確定是個大於0的數。

  2. 目標數的大小,確定會比數組的長度小。

從這兩個信息,咱們能夠獲得:

  1. 可以用正負號來作標記

  2. 能用經過數組的下標來進行標記

  3. 數組裏面,小於等於0的和大於數組長度的數都是不重要的數,大於0和小於等於數組長度的數都是重要的數

那麼作法就出來了:

  1. 走一遍,把數組裏面小於等於零的數和大於數組長度的數都設置成一個比數組長度要大的數

  2. 再走一遍,把數組以重要的數爲下標的元素都設置成負的

  3. 最後走一遍,碰到數組裏面第一個非負的數,他的下標就是咱們的答案

function fisrt_missing_positive(nums, nums_size)
    for i <- 1 to nums_size do
        if (nums[i] <= 0) or (nums[i] > nums_size) then
            nums[i] = nums_size + 1
        
    for i <- 1 to nums_size do 
        if (nums_size + 1 != nums[i]) then
            index = abs(nums[i])
            nums[index] = -1 * abs(nums[index]) 
            
    for i <- 1 to nums_size do 
        if (nums[i] < 0) then
            answer = i
            break
            
    return answer
相關文章
相關標籤/搜索