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.
  • Ref

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 中,完成了链表是否有环的判断。在此基础上,本题实现对环起点的判断和环长度的计算。

下面结合 LeetCode 141/142 - Linked List Cycle | CNBlogs 参考链接,对环起点的判断和环长度的计算进行分析。

leetcode-142.png

设链表起点距离环的起点距离为a,圈长为n,当 walkerrunner 相遇时,相遇点距离环起点距离为b,此时 runner 已绕环走了k圈,则

  • 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 相遇时,二者所在位置即环的起点。

证明过程如下。

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 可以了解数根的公式求解方法。

从上图总结规律,对于一个 b 进制的数字 (此处针对十进制数,b=10),其 数字根 (digit root) 可以表达为

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;
};

lbs0912
53 声望0 粉丝