LeetCode-Top 100題

Easy難度

771. Jewels and Stonescss

  • 題目: 給出兩個字符串A 和 B, 在B中找出在A中也出現過的字符
  • 思路: 新建一個HashSet,先遍歷A,把全部字符放到set裏,再遍歷B並判斷字符是否在set中出現。
// 02.14
class Solution {
    public int numJewelsInStones(String J, String S) {
        if (J == null || J.length() == 0) {
            return 0;
        }
        int count = 0;
        HashSet<Character> set = new HashSet<>();
        for (Character c : J.toCharArray()) {
            set.add(c);
        }
        for (Character c : S.toCharArray()) {
            if (set.contains(c)) {
                count++;
            }
        }
        
        return count;
    }
}
複製代碼

461. Hamming Distance 題目: 給出兩個整數,找出兩個整數變爲二進制格式時有幾個bit位不一樣 思路: 直接異或操做找不一樣?Yes,異或操做的結果是相同爲爲0,不一樣位爲1,將異或後獲得的數字中全部的1相加就是Hamming距離java

class Solution {
    public int hammingDistance(int x, int y) {
        int xor = x ^ y, count = 0;
        for (int i = 0; i < 32; i++) {
            // 右移操做等價於除以2^n
            count += (xor >> i) & 1; // n & 1 若是以1結尾,獲得1, 若是以0結尾,獲得0
        }
        return count;
    }
}
複製代碼

Similar question:

    1. Number of 1 Bits
    • 題目:求一個整數二進制中1出現的次數
    • 思路:
    public class Solution {
        // you need to treat n as an unsigned value
        public int hammingWeight(int n) {
            int count = 0;
            
            // 這裏也能夠用另外一個判斷條件 while (n != 0)
            for (int i = 0; i < 32; i++) {
                count += n & 1;
                n = n >>> 1;    
            }
            
            return count;
        }
    }
    複製代碼
    1. Counting Bits
    • 題目: 給出一個整數n,求出在[0,n]範圍內的每一個整數二進制表示中1出現的次數
    • 思路: 觀察規律,[2^1, 2^2], [2^2, 2^3]的前半部分是[2^1,2^2], 後半部分是[2^1,2^2]+1
0    0000    0
-------------
1    0001    1
-------------
2    0010    1
3    0011    2
-------------
4    0100    1
5    0101    2
6    0110    2
7    0111    3
-------------
8    1000    1
9    1001    2
10   1010    2
11   1011    3
12   1100    2
13   1101    3
14   1110    3
15   1111    4
複製代碼
public int[] countBits(int num) {
    int[] f = new int[num + 1];
    for (int i=1; i<=num; i++) {
        f[i] = f[i >> 1] + (i & 1); //用一個dp數組來存已經判斷過的信息
    }
    return f;
}
複製代碼

617. Merge Two Binary Treesnode

  • 題目: 將兩個二叉樹合併爲一個二叉樹
  • 思路: 注意必須是將樹的節點合併而不僅是值合併
// 02.14
class Solution {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        if (t1 == null) {
            return t2;
        }    
        if (t2 == null) {
            return t1;
        }
        TreeNode root = new TreeNode(t1.val + t2.val);
        root.left = mergeTrees(t1.left, t2.left);
        root.right = mergeTrees(t1.right, t2.right);
        
        return root;
    }
}
複製代碼

104. Maximum Depth of Binary Tree算法

// 02.14
class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        
        return Math.max(left, right) + 1;
    }
}
複製代碼

110. Balanced Binary Tree數組

  • 思路: 每一層都求一次深度,若是左右子樹的深度差值超過1,就是非平衡的二叉樹
// 02.14
class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) {
            return true;
        }
        
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        
        if (Math.abs(left - right) > 1) {
            return false;
        }
        
        return isBalanced(root.left) && isBalanced(root.right);
    }
    
    private int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        
        return Math.max(left, right) + 1;
    }
}
複製代碼

136. Single Numberbash

  • 題目: 給出一個數組,其中只有一個元素出現一次,其餘全部的元素都出現了兩次,請找出只出現一次的元素
  • 思路: 使用異或的特性,相同位相加獲得0,不一樣位相加獲得1
// 02.14
// 利用 A XOR A = 0的特色,保證
class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        for (int num : nums) {
            res = res ^ num;
        }
        return res;
    }
}
複製代碼

137. Single Number IIapp

  • 題目: 給出一個數組,其中只有一個元素出現一次,其餘全部的元素都出現了三次,請找出只出現一次的元素

260. Single Number III[M]函數

  • 題目: 給出一個數組,裏面有兩個元素只出現一次,其餘元素都出現了兩次,找到只出現一次的元素
  • 思路: 調用兩次異或操做,第一次將兩個出現一次的元素分到兩個不一樣的組, 第二次調用找出這兩個元素
public class Solution {
    public int[] singleNumber(int[] nums) {
        // Pass 1 : 
        // Get the XOR of the two numbers we need to find
        int diff = 0;
        for (int num : nums) {
            diff ^= num;
        }
        // Get its last set bit
        diff &= -diff;
        
        // Pass 2 :
        int[] rets = {0, 0}; // this array stores the two numbers we will return
        for (int num : nums)
        {
            if ((num & diff) == 0) // the bit is not set
            {
                rets[0] ^= num;
            }
            else // the bit is set
            {
                rets[1] ^= num;
            }
        }
        return rets;
    }
}
複製代碼

Missing Numberpost

  • 題目: 給出一個數組其中元素的範圍是0, 1, 2, ..., n 求出缺乏的那個數字
  • 思路: 利用異或特性,i和nums[i]的取值範圍除一個missing number以外都相同
  • 變形: 若是是排好序的數組直接用二分法,比較中間值的下標和元素值,若是下標比元素值,左邊的元素少,missin number在左邊,反之在右邊。
public int missingNumber(int[] nums) { //xor
    int res = nums.length; // 這裏須要將res初始值設定爲n,而不是0, 若是設定爲0的話,0會出現三次
    for(int i=0; i<nums.length; i++){
        res ^= i;
        res ^= nums[i];
    }
    return res;
}
複製代碼

287. Find the Duplicate Numberui

226. Invert Binary Tree

  • 問題: 將一個二叉樹的左右子樹顛倒
  • 思路: DC算法,左換右,左左換右右,右右換左左
// 02.17 
class Solution {
    public TreeNode invertTree(TreeNode root) {
    // bottom-up 解法
        if (root == null) {
            return null;
        }
        TreeNode left = invertTree(root.left);
        TreeNode right = invertTree(root.right);
        root.left = right;
        root.right = left;
        
        return root;
    }
}
複製代碼

101. Symmetric Tree

  • 問題: 判斷一棵二叉樹是不是中心對稱的
  • 思路: 左子樹的左節點要和右子樹的右節點中心對稱
class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;
        }
        return helper(root.left, root.right);
    }
    
    public boolean helper(TreeNode left, TreeNode right) {
        if (left == null || right == null) {
            return left == right;
        }
        if (left.val != right.val) {
            return false;
        }
        // 這裏必需要繼續判斷當前節點的子節點是否知足條件
        return helper(left.right, right.left) && helper(left.left, right.right);
    }
}
複製代碼

283. Move Zeroes

  • 問題: 給出一個數組,將數組中全部的0移動到數組的最後,並保持原來非零元素的相對順序
  • 思路: 同向雙指針, 交換第一個0元素和第一個非零元素
  • 樣例:
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]
複製代碼
// 02.17
class Solution {
    public void moveZeroes(int[] nums) {
        int n = nums.length;
        int left = 0;
        int right = 0;
        
        while (left < n && right < n) {
            while (right < n && nums[right] == 0) {
                right++;
            }
            // 這裏要保證left指針在right指針的前面
            while (left < right && nums[left] != 0) {
                left++;
            }
            
            if (left < n && right < n) {
                swap(nums, left, right);
                left++;
                right++;
            }
        }
    }
    
    private void swap(int[] nums, int i, int j) {
        int swap = nums[i];
        nums[i] = nums[j];
        nums[j] = swap;
    }
}

class Solution {
    public void moveZeroes(int[] nums) {
        int n = nums.length;
        int left = 0, right = 0;
        wihle (right < n) {
            if (nums[right] != n) {
                //當left 和 right指向了同一個元素時,能夠本身和本身swap,這樣保證了left必定指向一個0元素,right指向一個非零元素
                swap(nums, left, right); 
                left++;
            }
            right++;
        }
    }
    
    private void swap(int[] A, int i, int j) {
        int swap = A[i];
        A[i] = A[j];
        A[j] = swap;
    }
}
複製代碼

448. Find All Numbers Disappeared in an Array

  • 題目: 給出一個數組,每一個元素的取值範圍是[1,n] n是數組的長度,每一個元素能夠出現兩次或者一次,找出[1,n]中的哪些元素沒有在數組中出現
  • 思路: 利用性質(1): 每一個元素的取值範圍是[1,n],能夠看作是一個數組的index, 將其做爲數組的標記nums[index] = -nums[index]
class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
        List<Integer> res = new ArrayList<>();
        
        for (int i = 0; i < nums.length; i++) {
            int index = Math.abs(nums[i]) - 1;
            if (nums[index] > 0) {
                nums[index] = -nums[index];
            }
        }
        
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0) {
                res.add(i + 1); // 注意這裏要將index轉換爲元素時須要進行 +1 操做
            }
        }
        
        return res;
    }
}
複製代碼

Similar Question:

  • 41. First Missing Positive[Hard]
  • 題目: 給出一個整數型元素, 數組內的元素取值能夠是正或負數, 返回缺失的最小的正整數 要求O(n)時間複雜度和O(1)空間複雜度
  • 思路: 由於是要求缺失的最小整數,其實也限定了一個取值的範圍必需要從小到大, 由於不能使用額外空間,就直接使用給出的input數組做爲咱們的範圍,取值範圍就是[1,n] n是給出數組的長度, 接下來咱們要作的就是將input當中已經出現過的取值範圍在[1,n]之中的元素標記出來,作法是將出現過的元素對應的index取負值,相似448中的思路, 可是須要注意數組越界的狀況,須要限定num <= nums.length
  • 講解視頻: https://www.youtube.com/watch?v=8DqewGsVNkI
// 02.17 02.18
class Solution {
    public int firstMissingPositive(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 1;
        }
        int n = nums.length;
        // 先將負數和零單獨標記出來
        for (int i = 0; i < n; i++) {
            if (nums[i] <= 0) {
                nums[i] = Integer.MAX_VALUE;
            }
        }
        for (int i = 0; i < n; i++) {
            int index = Math.abs(nums[i]);
            if (index <= n) {
                nums[index - 1] = -Math.abs(nums[index - 1]);
            }
        }
        for (int i = 0; i < n; i++) {
            if (nums[i] > 0) {
                return i + 1;
            }
        }
        return n + 1; // 這裏返回的應該是 n + 1
    }
}  }
}

複製代碼

206. Reverse Linked List

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
}

// 02.23 遞歸實現-先走到鏈表最後而後向前指
class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode curr = head;
        ListNode next = head.next;
        curr.next = null;
        ListNode newHead = reverseList(next);
        next.next = curr;
        return newHead;
    }
}
複製代碼

Similar Question:

  • 92. Reverse Linked List II
  • 題目: 翻轉一個鏈表中m到n的元素, 1 <= m <= n
  • 思路:用一個變量計數? 分段處理,在m以前直接順序遍歷,在m到n之間須要reverse
//02.17 寶典的解法-沒看懂
public class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        if (m == n) {
            return head;
        }
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        
        ListNode prev = dummy;
        ListNode cur = head;
        
        for (int i = 0; i < m - 1; i++) {
            prev = prev.next;
            cur = cur.next;
        }
        
        for (int i = 0; i < n - m; i++) {
            ListNode next = cur.next;
            cur.next = next.next;
            next.next = prev.next;
            prev.next = next;
        }
        
        return dummy.next;
    }
}

//02.17 本身根據basketwang的代碼改寫的
//核心思路就是將mNode依次插入到nNode的後面直到mNode和nNode重合
class Solution {
    public ListNode reverseBetween(ListNode head, int m, int n) {
        if (m == n) {
            return head;
        }
        
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode prevM = dummy;
        ListNode mNode = head;
        ListNode nNode = head;
        for (int i = 0; i < m - 1; i++) {
            prevM = prevM.next;
            mNode = mNode.next;
            nNode = nNode.next;
        }
        
        for (int i = 0; i < n - m; i++) {
            nNode = nNode.next;
        }
        
        while (mNode != nNode) {
            prevM.next = mNode.next;
            mNode.next = nNode.next;
            nNode.next = mNode;
            mNode = prevM.next;
        }
        
        return dummy.next;
    }
}

複製代碼
  • 143. Reorder List
  • 題目: Given a singly linked list L: L0→L1→…→Ln-1→Ln, reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
  • 思路: 先將後半段的鏈表倒序,而後雙指針遍歷,將後半段的鏈表節點依次插入到前半段的鏈表中
class Solution {
    public void reorderList(ListNode head) {
        if (head == null || head.next == null) {
            return;
        }
        ListNode fast = head;
        ListNode slow = head;
        
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode tail = reverseList(slow.next);
        slow.next = null;
        merge(head, tail);
    }
    
    private ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode curr = head;
        while (curr != null) {
            ListNode next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
    
    private void merge(ListNode l1, ListNode l2) {
        int index = 0;
        ListNode dummy = new ListNode(0);
        ListNode curr = dummy;
        while (l1 != null && l2 != null) {
            if (index % 2 == 0) {
                curr.next = l1;
                l1 = l1.next;
            } else {
                curr.next = l2;
                l2 = l2.next;
            }
            curr = curr.next;
            index++;
        }
        if (l1 == null) {
            curr.next = l2;
        }
        if (l2 == null) {
            curr.next = l1;
        }
    }
}
複製代碼

169. Majority Element

  • 問題:給出一個數組,找出出現次數超過一半的元素
  • 思路:這個元素的出現次數之和必定大於其它全部元素的和, 須要用兩個變量來存, 一個存出現次數,一個存元素數值。
class Solution {
    public int majorityElement(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int res = nums[0];
        int count = 1;
        for (int i = 1; i < nums.length; i++) {
            if (res != nums[i]) {
                if (count > 0) {
                    count--;
                }
                else {
                    res = nums[i];
                    count++;
                }
            } else {
                count++;
            }
        }
        return res;
    }
}
複製代碼

** 538. Convert BST to Greater Tree**

  • 問題: 給出一個BST, 將BST中的每一個節點值加上全部比它大的節點值之和
  • 思路: 後序遍歷 並用一個變量來存當前全部遍歷過的節點的累加和
class Solution {
    int sumVal = 0;
    public TreeNode convertBST(TreeNode root) {
        if (root == null) {
            return null;
        }
        root.right = convertBST(root.right);
        sumVal += root.val; // 先更新sumVal爲當前節點值 + 累計sumVal
        root.val = sumVal; // 再直接更新root.val 爲sumVal
        root.left = convertBST(root.left);
        
        return root;
    }
}
複製代碼

121.Best Time to Buy and Sell Stock

  • 問題: 只容許買賣一次,求最大收益
// 02.18
class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }
        int min = prices[0];
        int maxProfit = 0;
        for (int i = 0; i < prices.length; i++) {
            if (prices[i] < min) {
                min = prices[i];
                continue;
            }
            maxProfit = Math.max(maxProfit, prices[i] - min);
        }
        
        return maxProfit;
    }
}
複製代碼
  • Follow Up:
  • 參考總結: https://blog.csdn.net/Dr_Unknown/article/details/51939121
  • 122. Best Time to Buy and Sell Stock II
  • 問題: 不限制交易次數買賣股票,求最大收益
  • 思路: 從頭遍歷數組,若是當天股票價格大於前一天就賣, 貪心算法
// 02.18
class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }
        int maxProfit = 0;
        for (int i = 1; i < prices.length; i++) {
            if (prices[i] - prices[i - 1] > 0) {
                maxProfit += prices[i] - prices[i - 1];
            }
        }
        
        return maxProfit;
    }
}
複製代碼
  • 123. Best Time to Buy and Sell Stock III
  • 問題: 只容許買賣兩次,求最大收益
  • 思路: 用動態規劃,以第i天做爲分界,判斷在第i天以前作一次交易的最大收益和第i天以後作一次交易的最大收益,最後遍歷兩個數組求和
// 02.18

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length < 2) return 0;
        
        int n = prices.length;
        int[] preProfit = new int[n];
        int[] postProfit = new int[n];
        
        int curMin = prices[0];
        for (int i = 1; i < n; i++) {
            curMin = Math.min(curMin, prices[i]);
            preProfit[i] = Math.max(preProfit[i - 1], prices[i] - curMin);//第i天賣出
        }
        
        int curMax = prices[n - 1];
        for (int i = n - 2; i >= 0; i--) {//從後往前遍歷 若是當天的收益大於以前的最大收益,就更新收益的數組
            curMax = Math.max(curMax, prices[i]); 
            postProfit[i] = Math.max(postProfit[i + 1], curMax - prices[i]);//第i天買入
        }
        
        int maxProfit = 0;
        for (int i = 0; i < n; i++) {
            maxProfit = Math.max(maxProfit, preProfit[i] + postProfit[i]);
        }
        
        return  maxProfit;
    }
複製代碼
  • Best Time to Buy and Sell Stock IV 沒看懂 跳過
  • 問題: 最多進行k次交易, 求最大收益, k做爲一個變給出
  • 思路: 若是k > n / 2, 直接按照買股票II來作,貪心只要當天比前一天股價高就賣 定義localMax 和 globalMax 兩個二維數組? 爲何? localMax必須在當前位置結束 globalMax記錄可能的不連續性
public class Solution {
    public int maxProfit(int k, int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }
        int n = prices.length;
        if (k >= n / 2) {
            int profit = 0;
            for (int i = 1; i < n; i++) {
                int diff = prices[i] - prices[i - 1];
                if (diff > 0) {
                    profit += diff;
                }
            }
            return profit;
        }
        
        int[][] localMax = new int[n][k + 1];
        int[][] globalMax = new int[n][k + 1];
        
        for (int i = 1; i < n; i++) {
            int diff = prices[i] - prices[i - 1];
            for (int j = 1; j <= k && j * 2 <= i + 1; j++) {
                localMax[i][j] = Math.max(localMax[i - 1][j], globalMax[i - 1][j - 1]) + diff;
                globalMax[i][j] = Math.max(localMax[i][j], globalMax[i - 1][j]);
            }
        }
        
        return globalMax[n - 1][k];
    }
}

複製代碼

53. Maximum Subarray

  • 問題: 給出一個數組, 找出數組中和最大的子數組
  • 思路: 定義一個localMax 和一個globalMax, localMax 是連續的子數組區間 Math.Max(localMax + nums[i], nums[i])
class Solution {
    public int maxSubArray(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int cur = nums[0];
        int max = nums[0];
        for (int i = 1; i < nums.length; i++) {
            cur = Math.max(cur + nums[i], nums[i]); // localMax更新必需要考慮當前位置的元素
            max = Math.max(cur, max); // globalMax的更新只須要比較自身和localMax兩個值便可
        }
        
        return max;
    }
}
複製代碼
  • Follow Up:
  • 152. Maximum Product Subarray
  • 問題: 給出一個數組,求其中乘積最大的子數組
  • 思路: 因爲存在負負得正,須要同時記錄localMaxlocalMin兩個local變量和一個globalMax變量
//02.18 必須注意初始化爲nums[0]
class Solution {
    public int maxProduct(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int localMax = nums[0];
        int localMin = nums[0];
        int globalMax = nums[0];
        for (int i = 1; i < nums.length; i++) {
        //必需要在比較以前先用新的變量將localMax * nums[i] 和 localMin * nums[i]存起來,不然比較的時候不一樣步
            int currMax = localMax * nums[i];
            int currMin = localMin * nums[i];
            localMax = Math.max(Math.max(currMax, currMin), nums[i]);
            // 這裏會出現localMin使用更新後的localMax的結果, 須要保證localMax和localMin的同步
            localMin = Math.min(Math.min(currMax, currMin), nums[i]);
            globalMax = Math.max(localMax, globalMax);
        }
        
        return globalMax;
    }
}
複製代碼
  • 42. Maximum SubarrayII
  • 問題: 給出一個數組,找出兩個不重疊的子數組使其和最大
  • 思路: 須要找到的是兩個子數組, 如何進行切割 每一個位置均可以做爲切割點
//02.18
public class Solution {
    public int maxTwoSubArrays(ArrayList<Integer> nums) {
        if (nums == null || nums.size() == 0) {
            return 0;
        }
        int n = nums.size();
        int[] left = new int[n];
        int[] right = new int[n];
        
        int localMax = nums.get(0);
        int max = nums.get(0);
        left[0] = nums.get(0);
        for (int i = 1; i < n; i++) {
            localMax = Math.max(nums.get(i), nums.get(i) + localMax);
            max = Math.max(max, localMax);
            left[i] = max; 
        }
        
        localMax = nums.get(n - 1);
        max = nums.get(n - 1);
        right[n - 1] = nums.get(n - 1);
        for (int i = n - 2; i >= 0; i--) {
            localMax = Math.max(nums.get(i), nums.get(i) + localMax);
            max = Math.max(max, localMax);
            right[i] = max;
        }
        
        int res = Integer.MIN_VALUE;
        for (int i = 0; i < n - 1; i++) {
            res = Math.max(res, left[i] + right[i + 1]); // 爲何要用right[i + 1]??
        }
        
        return res;
    }
}
複製代碼
  • Maximum Subarray III
  • 問題: 給出一個整數數組,找出k個不重疊且和最大的子數組
  • 思路:

字典序最大的子序列

// 02.14
public class Main { 
public static void main(String[] args) { 
    Scanner input = new Scanner(System.in); 
    String str = input.nextLine(); 
    char[] res = str.toCharArray(); 
    ArrayList<Character> arr = new ArrayList<>(); 
    arr.add(res[res.length-1]); 
    for (int i = res.length-1; i > 0; i--){ 
        if ( arr.get(arr.size()-1) <= res[i-1]){ 
            arr.add(res[i-1]);            
        }        
    }        
    StringBuilder sb = new StringBuilder();        
    for (int i = 0; i < arr.size(); i++){            
        sb.append(arr.get(i));        
    }        
    System.out.println(sb.reverse().toString());    
    }
}
複製代碼

160.Intersection of Two Linked List

  • 問題: 給出兩個鏈表,它們的後半段是相交的,也就是後半段徹底一致,求出交點的起始位置
  • 思路: 因爲後半段一致,當第一次同時走到相同的節點是就是第一個交點,關鍵問題是前半段的長度不一致,若是從同一塊兒點來作就能夠作到同步到達交點
// 02.18
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode currA = headA;
        ListNode currB = headB;
        int lenA = 0;
        int lenB = 0;
        while (currA != null) {
            currA = currA.next;
            lenA++;
        }
        
        while (currB != null) {
            currB = currB.next;
            lenB++;
        }
       
        while (lenA - lenB > 0) {
            headA = headA.next;
            lenA--;
        }

        while (lenB - lenA > 0) {
            headB = headB.next;
            lenB--;                
        }
        
        while (headA != headB) {
            headA = headA.next;
            headB = headB.next;
        }
        
        return headA;
    }
}

//兩次遍歷利用差值來直接 a + b + c
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        ListNode a = headA;
        ListNode b = headB;
        
        while (a != b) {
            a = a == null ? headB : a.next;
            b = b == null ? headA : b.next;
        }
        return a;
    }
}

複製代碼

438.Find All Anagrams in a String

  • 問題: 給出兩個字符串s和p, 找出
  • 思路: 滑動窗口,窗口的長度爲p.length()並設定一個輔助變量diff來記錄當前窗口內的全部字符與p字符串的比較結果
class Solution {
    public List<Integer> findAnagrams(String s, String p) {                         
        ArrayList<Integer> res = new ArrayList<>();
        if (s.length() == 0 || p.length() == 0 || s.length() < p.length()) {
            return new ArrayList<Integer>();
        }
        // store the characters we need for finding next anagram
        int[] chars = new int[26];
        for (Character c : p.toCharArray()) {
            chars[c - 'a']++;
        }
        int matched = 0;
        int plength = p.length();
        int slength = s.length();
        int left = 0; // point to String s
        int right = 0; // point to String p
        while (right < slength) {
            if (chars[s.charAt(right) - 'a'] >= 1) {
                matched++;
            }
            if (matched == plength) {
                res.add(left);
            }
            chars[s.charAt(right) - 'a']--;
            right++;
            if (right - left == plength) {
                // 當前left位置的字符在p中也出現過,走到下一步時會被推出當前窗口,因此matched須要減一
                if (chars[s.charAt(left) - 'a'] >= 0) {
                    matched--;
                }
                // 當前left向前走以後,須要匹配的元素多了一個,須要將chars中的記錄+1
                chars[s.charAt(left) - 'a']++;
                left++;
            }
        }
        return res;
    }
}
複製代碼
  • Similar Question:
  • 242.Valid Anagram
  • 問題: 給出兩個字符串s和t,判斷t是不是s的Anagram
  • 思路: 先比較長度,長度不一致必定是false,再用一個數組存s中的全部出現的字符
class Solution {
    public boolean isAnagram(String s, String t) {
        int[] alphabet = new int[26];
        for (int i = 0; i < s.length(); i++) alphabet[s.charAt(i) - 'a']++;
        for (int i = 0; i < t.length(); i++) alphabet[t.charAt(i) - 'a']--;
        for (int i : alphabet) if (i != 0) return false;
        return true;
    }
}
複製代碼

581. Shortest Unsorted Continuous Subarray


Medium

94. Binary Tree Inorder Traversal

// 02.15
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();

        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode cur = root;

        while(cur!=null || !stack.empty()){
            while(cur!=null){
                stack.add(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            list.add(cur.val);
            cur = cur.right;
        }

        return list;
    }
}
複製代碼

** 95. Unique Binary Search Trees II**

  • 問題:
  • 思路:

230. Kth Smallest Element in a BST[M]

  • 題目: 找到一個BST當中第K大的數值
  • 思路: 中序遍歷倒計時
class Solution {
    
  private static int number = 0;
  private static int count = 0;

  public int kthSmallest(TreeNode root, int k) {
      count = k;
      helper(root);
      return number;
  }
  
  public void helper(TreeNode n) {
      if (n.left != null) helper(n.left);
      count--;
      if (count == 0) {
          number = n.val;
          return;
      }
      if (n.right != null) helper(n.right);
  }
}
複製代碼
  • 思路: 利用BST的特性,中序遍歷
// 02.14
class Solution {
    public int kthSmallest(TreeNode root, int k) {
        Stack<TreeNode> stack = new Stack<>();
        
        TreeNode cur = root;
        
        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.add(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            k--;
            if (k == 0) {
                return cur.val;
            }
            cur = cur.right;
        }
        
        return -1;
    }
}
複製代碼

285.Inorder Successor in BST

  • 問題: 找出一個node 的中序遍歷的下一個節點
  • 思路: 直接inorde traversal
// 02.15
class Solution {
    public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode cur = root;
        boolean found = false;
        
        while(cur!=null || !stack.empty()){
            while(cur!=null){
                stack.add(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            if (found == true) {
                return cur;
            }
            if (cur == p) {
                found = true;
            }

            cur = cur.right;
        }
        
        return null;
    }
}

複製代碼

510.Inorder Successor in BST II

  • 問題: 找出BST中某個節點的下一個相鄰節點,只給出parent, left, right指針而不給出root節點
  • 思路: 分類討論不一樣Successor
    • Case 1: 當前節點的右子節點存在,那麼successor就是右子樹的最左節點
    • Case 2: 若是當前節點的右子樹不存在,向上找parent,直到找到一個比當前節點大的parent node就是succsssor, 若是找不到最後會返回null也就是root.parent
class Solution {
    public Node inorderSuccessor(Node x) {
        if (x.right == null) {
            Node result = x.parent;
            while (result != null && result.val < x.val) {
                result = result.parent;
            }
            return result;
        } else {
            Node result = x.right;
            while (result.left != null) {
                result = result.left;
            }
            return result;
        }
    }
}
複製代碼

333. Largest BST Subtree

  • 問題: 找出一個二叉樹中包含最多節點的BST子樹
  • 思路: 先要找最大的子樹, 再保證是一個BST
複製代碼

98. Validate Binary Search Tree

  • 問題: 肯定一個二叉樹是不是一個BST
  • 思路: Inorder 順序遍歷必需要是遞增的, 設一個pre指針, 初始值爲null,每次遍歷到新的節點是進行更新
//02.15
public boolean isValidBST(TreeNode root) {
   if (root == null) return true;
   Stack<TreeNode> stack = new Stack<>();
   TreeNode pre = null;
   while (root != null || !stack.isEmpty()) {
      while (root != null) {
         stack.push(root);
         root = root.left;
      }
      root = stack.pop();
      if(pre != null && root.val <= pre.val) return false;
      pre = root;
      root = root.right;
   }
   return true;
}
複製代碼

215. Kth Largest Elements in an Array

  • 題目: 給出一個數組,找到數組中第k大的數值
  • 思路: 根據快排的partition分類思路,先找一個pivot值,而後將比pivot值大的數放在右邊,比pivot小的數字都放在左邊,每次分好以後,判斷一下pivot所在的位置是否等於k,若是等於,那麼直接返回pivot值,若是k <= right + 1, 說明第k大的數必定在pivot左邊,遞歸調用partition判斷左半部分,若是k > right + 1, 判斷右半部分。
public class Solution {
    public int findKthLargest(int[] nums, int k) {
        return partition(nums, k, 0, nums.length - 1);
    }

    private int partition(int[] nums, int k, int start, int end){

        int pivot = nums[start];
        int left = start;
        int right = end;

        while(left <= right){
            while(left <= right && nums[left] >= pivot) left++;
            while(left <= right && nums[right] <= pivot) right--;
            if(left < right) swap(nums, left, right);
        }
        swap(nums, start, right);
    
        if(k == right + 1) return nums[right];
        if(k > right + 1){
            return partition(nums, k, right + 1, end);
        } else {
            return partition(nums, k, start, right - 1);
        }
    }
287. Find the Duplicate Number private void swap(int[] nums, int a, int b){
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }
}
複製代碼

follow up: 378. Kth Smallest Element in a Sorted Matrix

  • 題目: 給出一個n * n的二維數組,每一行和每一列都是遞增的,可是不保證蛇形有序, 求出這個數組中第K大的數值
  • 思路1: 直接遍歷全部元素並用最大堆維護前K小的元素,當pq.size() > k的時候將pq中的Top元素poll出來
  • 思路2: 使用二分查找,不是簡單的查找某個元素是否存在而是須要找出比某一個值小的元素的個數,定義一個countLessEqualNumsfunction, 本身定義的target
// 02.17
class Solution {
    // matrix is n * n
    public int kthSmallest(int[][] matrix, int k) {
        int start = matrix[0][0];
        int end = matrix[matrix.length - 1][matrix[0].length - 1];
        while (start <= end) {
            // count the numbers that is smaller than or equal to the mid
            int mid = start + (end - start) / 2; // 這個mid值必定存在麼?
            int count = countLessEqualNums(mid, matrix);
            if (count < k) {
                start = mid + 1;
            } else {
                end = mid - 1;
            }
        }
        return start;
    }
    private int countLessEqualNums(int target, int[][] matrix) {
        int i = 0;
        int j = matrix[0].length - 1;
        int start = matrix[i][j];
        int result = 0;
        while (i < matrix.length && j >= 0) {
            if (matrix[i][j] > target) {
                j--;
            }  else {
                result += j + 1;
                i++;
            }
        }
        return result;    
    }
}
複製代碼

similar questions:

  • 74.Search in 2D Matrix
  • 題目: 給出一個二維的數組,判斷一個特定target值是否在數組中存在
  • 思路: 由於每一行都是遞增的且每一行的最後一個元素總小於當前行的下一行的首元素,因此整個二維數組能夠看作一個有序的一維數組, 一維轉二維 [mid/cols]獲得行數 [mid%cols]獲得列數
  • 思路2: 和Search in 2D Matrix II 一樣解法
public class Solution {
    /** * @param matrix, a list of lists of integers * @param target, an integer * @return a boolean, indicate whether matrix contains target */
    public boolean searchMatrix(int[][] matrix, int target) {
        // write your code here
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
            return false;
        }
        
        int row = matrix.length;
        int column = matrix[0].length;
        
        int start = 0, end = row * column - 1;
        while(start <= end){
            int mid = start + (end - start) / 2;
            int number = matrix[mid / column][mid % column];
            if(number == target){
                return true;
            }else if(number > target){
                end = mid - 1;
            }else{
                start = mid + 1;
            }
        }
        
        return false;
        
    }
}
複製代碼
  • Search in 2D Matrix II
  • 問題:給出一個二維數組,每一行都是遞增的,每一列都是遞增的,但不保證蛇形有序,問數組中是否存在一個特定的值
  • 思路: 看到有序排列就要使用Binary Search, Binary Search的核心是找到比較的區間, 起點是左下角的元素, 若是查找的元素大於
[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
複製代碼
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0) {
            return false;
        }
        
        int col = 0;
        int row = matrix.length - 1;
        while (row >= 0 && col < matrix[0].length) {
            if (target == matrix[row][col]) {
                return true;
            }
            else if (target < matrix[row][col]) {
                row--;
            }
            else if (target > matrix[row][col]) {
                col++;
            }
        }
        
        return false;
    }
}
複製代碼
  • 703. Kth Largest Element in a Stream
  • 問題: 給出一個不斷增長的字節流,寫一個函數返回當前第K大的數字
  • 思路: 維持一個Min Heap來保存前K大的元素,若是新加入的數字大於當前的第K大,則更新當前的第K大,若是小於當前的第K大則不作任何更新
class KthLargest {
     final PriorityQueue<Integer> q;
     final int k;
    public KthLargest(int k, int[] nums) {
        this.k = k;
        q = new PriorityQueue<Integer>(k);
        for (int a :nums) {
            add(a); //這裏直接調用add() 而不是pq中默認的add()方法
        }
    }
    
    public int add(int val) {
        q.offer(val);
        if (q.size() > k) {
            q.poll();
        }
        return q.peek();
    }
}

* **329.Longest Increasing Path in a Matrix**
* 題目: 找出一個二維數組中一條最長的遞增路徑,並返回路徑的長度
* 思路: 直接DFS + memo來判斷每個位置做爲路徑的最小的元素(即路徑的起點)可以獲得的最長路徑的長度 
```java
// 02.16
public static final int[][] dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

public int longestIncreasingPath(int[][] matrix) {
    if(matrix.length == 0) return 0;
    int m = matrix.length, n = matrix[0].length;
    int[][] cache = new int[m][n];
    int max = 1;
    for(int i = 0; i < m; i++) {
        for(int j = 0; j < n; j++) {
            int len = dfs(matrix, i, j, m, n, cache);
            max = Math.max(max, len);
        }
    }   
    return max;
}

public int dfs(int[][] matrix, int i, int j, int m, int n, int[][] cache) {
    if(cache[i][j] != 0) return cache[i][j];
    int max = 1;
    for(int[] dir: dirs) {
        int x = i + dir[0], y = j + dir[1];
        // matrix[i][j] 是當前節點的值, 而matrix[x][y]是周圍的neighbor節點的值
        if(x < 0 || x >= m || y < 0 || y >= n || matrix[x][y] <= matrix[i][j]) continue;
        int len = 1 + dfs(matrix, x, y, m, n, cache);
        max = Math.max(max, len);
    }https://leetcode.com/problems/third-maximum-number/
    cache[i][j] = max;
    return max;
}
複製代碼

414. Third Maximum Number

  • 題目: 給出一個數組,找到數組中第三大的數字
  • 思路: 用三個變量分別存最大,第二大,第三大的數字, 遍歷數組並及時更新
class Solution {
    public int thirdMax(int[] nums) {
        long firstMax = Long.MIN_VALUE,secondMax = Long.MIN_VALUE,thirdMax = Long.MIN_VALUE;
        // 爲了解決[1,2,-2147483648]這種corner case
        for (int i = 0; i < nums.length; i++) {
            if(nums[i]> firstMax)
            {
                thirdMax = secondMax;
                secondMax = firstMax;
                firstMax = nums[i];
            }else if(nums[i]> secondMax && nums[i] < firstMax)
            {
                thirdMax = secondMax;
                secondMax = nums[i];
            }else if( nums[i] > thirdMax && nums[i] < secondMax)
            {
                thirdMax = nums[i];
            }
        }
        return (int)(thirdMax == Long.MIN_VALUE ? firstMax: thirdMax);
    }
}

複製代碼
相關文章
相關標籤/搜索