LeetCode Notes - 1

LeetCode Notes - 1

Overview

141 - Linked List Cycle

Description

Approach 1 - Hash Table

Analysis

  • 使用哈希表解決,時間複雜度爲 O(n),空間複雜度爲 O(n)
  • 遍歷鏈表,若遇到 Null,則 代表鏈表無環。若遍歷的節點在哈希表中已存在,則代表鏈表有環。

Solution

  • JavaScript
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    let nodesSeen = new Set();
    if(head === null  || head.next === null){
        return false;
    }
    while(head !== null){
        if(nodesSeen.has(head)){
            return true;
        }
        else{
            nodesSeen.add(head);
        }
        head = head.next;
    }
    return false;
};
  • Java
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

public boolean hasCycle(ListNode head) {
    Set<ListNode> nodesSeen = new HashSet<>();
    while (head != null) {
        if (nodesSeen.contains(head)) {
            return true;
        } else {
            nodesSeen.add(head);
        }
        head = head.next;
    }
    return false;
}

Approach 2 - Two Pointers

Analysis

  • 使用快慢指針解決,時間複雜度爲 O(n),空間複雜度爲 O(1)
  • Use two pointers, walker and runner.
  • Walker moves step by step.
  • Runner moves two steps at time.
  • If the Linked List has a cycle walker and runner will meet at some point.
  • Refjavascript

Solution

  • 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) {
        if(head == NULL){
            return false;
        }
        ListNode *walker = head; //moves one step each time
        ListNode *runner = head; //moves two step each time
        while(runner->next != NULL && runner->next->next != NULL){
            walker = walker->next;
            runner = runner->next->next;
            if(walker == runner){
                return true;
            }
        }
        return false;
    }
};
  • JavaScript
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
    if(head === null) {
        return false;
    }
    var walker = new ListNode();
    var runner = new ListNode();
    walker = head;
    runner = head;
    while(runner.next!==null && runner.next.next!==null) {
        walker = walker.next;
        runner = runner.next.next;
        if(walker === runner) return true;
    }
    return false;
};
  • Java
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }
}
  • Python
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        if head == None or head.next == None:
            return False
        slow = fast = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                return True
        return False

142 - Linked List Cycle II

Description

Approach 1 - Two Pointers

Analysis

LeetCode - 141. Linked List Cycle 中,完成了鏈表是否有環的判斷。在此基礎上,本題實現對環起點的判斷和環長度的計算。html

下面結合 LeetCode 141/142 - Linked List Cycle | CNBlogs 參考連接,對環起點的判斷和環長度的計算進行分析。java

leetcode-142.png

設鏈表起點距離環的起點距離爲a,圈長爲n,當 walkerrunner 相遇時,相遇點距離環起點距離爲b,此時 runner 已繞環走了k圈,則node

  • walker 走的距離爲 a+b,步數爲 a+b
  • runner 速度爲 walker 的兩倍,runner 走的距離爲 2*(a+b),步數爲 a+b
  • runner 走的距離爲 a+b+k*n=2*(a+b),從而 a+b=k*na=k*n-b
  • 所以有,當 walkera 步,runner(k*n-b) 步。當 k=1 時,則爲 (n-b)
環的起點

walker 返回鏈表初始頭結點,runner 仍在相遇點。此時,令 walkerrunner 每次都走一步距離。當 walkerrunner 相遇時,兩者所在位置即環的起點。python

證實過程以下。git

walkera 步,到達環的起點;runner 初始位置爲 2(a+b),走了 a 步以後,即 kn-b 步以後,所在位置爲 2(a+b)+kn-b=2a+b+kn= a+(a+b)+kn=a+2kn。所以,runner 位置是環的起點。正則表達式

// runner走的位置
2(a+b) + a
= 3a + 2b    //消去b  b = k*n - a
= 3a + 2*(k*n - a)
= a + 2kn
環的長度

在上述判斷環的起點的基礎上,求解環的長度。函數

  • walkerrunner 相遇時,兩者所在位置即環的起點。此後,再讓 walker 每次運動一步。
  • walkern 步以後,walkerrunner 再次相遇。walker 所走的步數便是環的長度。

Solution

注意,在 while() 中須要使用 break 及時跳出循環,不然提交時會出現超時錯誤 Time Limit Exceeded
  • C++
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
       if(head == NULL){
            return NULL;
        }
        bool hasCycle = false;
        ListNode *walker = head; //moves one step each time
        ListNode *runner = head; //moves two step each time
        while(runner->next != NULL && runner->next->next != NULL){
            walker = walker->next;
            runner = runner->next->next;
            if(walker == runner){
                hasCycle = true;
                break;  //跳出循環
            }
        }
        if(hasCycle == true){
            walker = head;
            while(walker != runner){
                walker = walker->next;
                runner = runner->next;
            }
            return walker;
        }
        return NULL;
        
    }
};
  • JavaScript
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var detectCycle = function(head) {
    if(head === null || head.next === null){
        return null;
    }
    // Tip - new ListNode() 建立可省略,節省代碼運行時間
    // let walker = new ListNode();   // one steps
    // let runner = new ListNode();   // two steps
    let walker = head;
    let runner = head;
    let hasCycle = false;
    while(runner.next !== null && runner.next.next !== null){
        runner = runner.next.next;
        walker = walker.next;
        if(runner === walker){
            hasCycle = true;
            break; //jump loop
        }
    }
    if(hasCycle){
        walker = head;
        while(walker !== runner){
            runner = runner.next;
            walker = walker.next;
        }
        return walker;
    }
    return null;
};
  • Java
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head == null || head.next == null){
            return null;
        }
        ListNode walker = head;
        ListNode runner = head;
        boolean hasCycle = false;
        while(runner.next != null && runner.next.next != null){
            walker = walker.next;
            runner = runner.next.next;
            if(walker == runner){
                hasCycle = true;
                break; //jump loop
            }
        }
        if(hasCycle){
            walker = head;
            while(walker != runner){
                walker = walker.next;
                runner = runner.next;
            }
            return walker;
        }
        return null;
    }
 
}
  • Python
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head == None or head.next == None:
            return None
        runner = walker = head
        hasCycle = False
        while runner and runner.next:
            runner = runner.next.next
            walker = walker.next
            if runner == walker:
                hasCycle = True
                break
        if hasCycle:
            walker = head
            while walker != runner:
                walker = walker.next
                runner = runner.next
            return walker
        return None

258 - Add Digits

Description

Approach 1 - Digit Root 公式

Analysis

將一正整數的各個位數相加(即橫向相加)後,若加完後的值大於等於10的話,則繼續將各位數進行橫向相加直到其值小於十爲止所獲得的數,即爲數根 ( Digit Root)

本題目爲求解一個非負整數的數根。參考 Digit Root | Wikipedia 能夠了解數根的公式求解方法。oop

從上圖總結規律,對於一個 b 進制的數字 (此處針對十進制數,b=10),其 數字根 (digit root) 能夠表達爲ui

dr(n) = 0 if n == 0    

dr(n) = (b-1) if n != 0 and n % (b-1) == 0  // 9的倍數且不爲零,數根爲9

dr(n) = n mod (b-1) if n % (b-1) != 0  // 不是9的倍數且不爲零,數根爲對9取模

或者

dr(n) = 1 + (n - 1) % 9

Solution

  • C++
class Solution 
{
public:
    int addDigits(int num) 
    {
        return 1 + (num - 1) % 9;
    }
};
  • JavaScript
/**
 * @param {number} num
 * @return {number}
 */
var addDigits = function(num) {
    return 1 + (num - 1) % 9;
};
  • Java
class Solution {
    public int addDigits(int num) {
        if (num == 0){
            return 0;
        }
        if (num % 9 == 0){
            return 9;
        }
        else {
            return num % 9;
        }
    }
}
  • Python
class Solution:
    def addDigits(self, num: int) -> int:
        """
        :type num:int
        :rtype :int
        """
        if num == 0: return 0
        elif num%9 == 0: return 9
        else: return num%9

461 - Hamming Distance

Description

Approach 1 - 異或位運算

對輸入參數進行異或位運算獲得一個二進制數值,再計算其中的數字 1 的個數便可。

在代碼實現中,能夠結合語言內置的API或方法,簡化求解過程。

Analysis

  • JavaScript
/**
 * @param {number} x
 * @param {number} y
 * @return {number}
 */
var hammingDistance = function(x, y) {
    let xor = x^y;
    let total = 0;
    for(let i=0;i<32;i++){   // Number型 佔32位
        total += (xor>>i) &1;
    }
    return total;
};

因爲 Number 型佔 32 位,所以,須要異或的結果進行32次移位,循環判斷其中的數字 1 的個數。

下面考慮簡化上述求解過程。

  1. number.toString(radix) 方法能夠將一個數字以 radix 進制格式轉換爲字符串。能夠將異或結果轉換爲 2 進制字符串。
  2. 對上述 2 進制字符串,使用正則表達式,只保留其中 1,將 0 替換爲空。
  3. 最後,計算所得字符串的長度,即所求結果。
/**
 * @param {number} x
 * @param {number} y
 * @return {number}
 */
var hammingDistance = function(x, y) {
     return (x ^ y).toString(2).replace(/0/g, '').length;
};
  • Java

Java中,Integer.bitCount() 函數能夠返回輸入參數對應二進制格式數值中數字 1 的個數。

public class Solution {
    public int hammingDistance(int x, int y) {
        return Integer.bitCount(x^y);  //XOR
    }
}
  • C++

C++ 中, int __builtin_popcount 函數能夠返回輸入參數對應二進制格式數值中數字 1 的個數。

class Solution {
public:
    int hammingDistance(int x, int y) {
        return __builtin_popcount(x^y);
    }
};

463 - Island Perimeter

Description

Approach 1

Analysis

  • 遍歷矩陣,找出 島嶼 islands 個數。若不考慮島嶼的周圍,則對應的周長爲 4 * islands
  • 對於島嶼,考慮其是否有左側和頂部的鄰居島嶼 neighbours。爲了簡化求解,對於全部島嶼,只考慮其左側和頂部的鄰居狀況。
  • 綜上,最終所求的周長爲 4 * islands - 2 * neighbours

Solution

  • Java
public class Solution {
    public int islandPerimeter(int[][] grid) {
        int islands = 0, neighbours = 0;

        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[i].length; j++) {
                if (grid[i][j] == 1) {
                    islands++; // count islands
                    if (i !=0 && grid[i - 1][j] == 1) neighbours++; // count top neighbours
                    if (j !=0 && grid[i][j - 1] == 1) neighbours++; // count left neighbours
                }
            }
        }

        return islands * 4 - neighbours * 2;
    }
}
  • C++
class Solution {
public:
    int islandPerimeter(vector<vector<int>>& grid) {
        int count = 0, repeat = 0;
        for (int i = 0; i<grid.size(); i++)
        {
            for (int j = 0; j<grid[i].size(); j++)
            {
                if (grid[i][j] == 1)
                {
                    count++;
                    if (i!= 0 && grid[i-1][j] == 1) repeat++;
                    if (j!= 0 && grid[i][j - 1] == 1) repeat++;
                }
            }
        }
        return 4 * count - repeat * 2;
    }
};
  • JavaScript
/**
 * @param {number[][]} grid
 * @return {number}
 */
var islandPerimeter = function(grid) {
    var count=0;
    var repeat=0;
    for(var i=0;i<grid.length;i++){
        for(var j=0;j<grid[i].length;j++){
            if(grid[i][j] === 1){
                count++;
                if((i!==0) && (grid[i-1][j]===1)){
                    repeat++;
                }
                if((j!==0) && (grid[i][j-1]===1)){
                    repeat++;
                }
            }
        }
    }
    return 4*count-2*repeat;
};
相關文章
相關標籤/搜索