leetcode刷题记录

语言:java
做题顺序:先数据结构,后算法;先easy,后medium
尽量都是选择高效点的解法,思路和复杂度有的忘记模板了

目录

搜索

1091. 二进制矩阵中的最短路径

思路
时间复杂度:O(N²)
空间复杂度:O(N²)

class Solution {
    public int shortestPathBinaryMatrix(int[][] grid) {
        if (grid[0][0] == 1) return -1;

        int n = grid.length;
        int[][] dist = new int[n][n];  // 起点到该点的最短距离

        for (int[] arr : dist) Arrays.fill(arr, Integer.MAX_VALUE);
        dist[0][0] = 1;

        Queue<int[]> queue = new ArrayDeque<int[]>();
        queue.offer(new int[]{0, 0});

        while (!queue.isEmpty()) {
            int[] arr = queue.poll();
            int x = arr[0], y = arr[1];
            if (x == n - 1 && y == n - 1) return dist[x][y];
            for (int dx = -1; dx < 2; dx++) {
                for (int dy = -1; dy < 2; dy++) {
                    if (x + dx < 0 || x + dx >= n || y + dy < 0 || y + dy >= n) continue;
                    else if (grid[x + dx][y + dy] == 1 || dist[x + dx][y + dy] <= dist[x][y] + 1) continue;
                    else {
                        dist[x + dx][y + dy] = dist[x][y] + 1;
                        queue.offer(new int[]{x + dx, y + dy});
                    }
                }
            }
        }
        return -1;
    }
}

695. 岛屿的最大面积

思路
时间复杂度:O(m*n)
空间复杂度:O(m*n)

class Solution {
    public int maxAreaOfIsland(int[][] grid) {
        int ans = 0;
        for (int i = 0; i != grid.length; i++) {
            for (int j = 0; j != grid[0].length; j++) {
                ans = Math.max(ans, IslandDfs(grid, i, j));
            }
        }
        return ans;
    }

    private int IslandDfs(int[][] grid, int x, int y) {
        if (x < 0 || y < 0 || x >= grid.length || y >= grid[0].length || grid[x][y] == 0) return 0;
        grid[x][y] = 0;
        return 1
                + IslandDfs(grid, x - 1, y)
                + IslandDfs(grid, x, y + 1)
                + IslandDfs(grid, x, y - 1)
                + IslandDfs(grid, x + 1, y);
    }
}

200. 岛屿数量

思路
时间复杂度:O(m*n)
空间复杂度:O(m*n)

class Solution {
    public int numIslands(char[][] grid) {
        int ans = 0;
        for (int i = 0; i != grid.length; i++) {
            for (int j = 0; j != grid[0].length; j++) {
                if (grid[i][j] == '1') ans += 1;
                numIslandsDfs(grid, i, j);
            }
        }
        return ans;
    }

    private void numIslandsDfs(char[][] grid, int x, int y) {
        if (x < 0 || y < 0 || x >= grid.length || y >= grid[0].length || grid[x][y] == '0') return;
        grid[x][y] = '0';
        numIslandsDfs(grid, x - 1, y);
        numIslandsDfs(grid, x, y + 1);
        numIslandsDfs(grid, x, y - 1);
        numIslandsDfs(grid, x + 1, y);
    }
}

130. 被围绕的区域

思路:特殊标记边界上的’O’为’#’
时间复杂度:O(m*n)
空间复杂度:O(m*n)

class Solution {
    int[] dx = new int[]{-1, 0, 0, 1};
    int[] dy = new int[]{0, 1, -1, 0};

    public void solve(char[][] board) {
        int[] x = new int[]{0, board.length - 1};
        int[] y = new int[]{0, board[0].length - 1};
        for (int i = 0; i < board.length; i++)
            for (int j : y)
                turnDFS(board, i, j);
        for (int i : x)
            for (int j = 0; j < board[0].length; j++)
                turnDFS(board, i, j);
        for (int i = 0; i < board.length; i++)
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == '#') board[i][j] = 'O';
                else if (board[i][j] == 'O') board[i][j] = 'X';
            }
    }

    private void turnDFS(char[][] board, int x, int y) {
        if (x < 0 || y < 0 || x >= board.length || y >= board[0].length || board[x][y] == '#' || board[x][y] == 'X')
            return;
        board[x][y] = '#';
        for (int k = 0; k < 4; k++) {
            turnDFS(board, x + dx[k], y + dy[k]);
        }
    }
}

417. 太平洋大西洋水流问题

思路:水往高处流,取交集得出结果
时间复杂度:O(mn)
空间复杂度:O(m
n)

class Solution {
    int[][] heights;
    int m, n;
    int[] dx = new int[] { -1, 0, 0, 1 };
    int[] dy = new int[] { 0, 1, -1, 0 };

    public List<List<Integer>> pacificAtlantic(int[][] heights) {
        this.heights = heights;
        this.m = heights.length;
        this.n = heights[0].length;
        boolean[][] pacific = new boolean[m][n];
        boolean[][] atlantic = new boolean[m][n];

        for (int x = 0; x < m; x++) waterDFS(pacific, x, 0);
        for (int y = 1; y < n; y++) waterDFS(pacific, 0, y);
        for (int x = 0; x < m; x++) waterDFS(atlantic, x, n - 1);
        for (int y = 0; y < n-1; y++) waterDFS(atlantic, m - 1, y);

        List<List<Integer>> result = new ArrayList<List<Integer>>();
        for (int i = 0; i < m; i++)
            for (int j = 0; j < n; j++)
                if (pacific[i][j] && atlantic[i][j]) {
                    List<Integer> t = new ArrayList<Integer>();
                    t.add(i);
                    t.add(j);
                    result.add(t);
                }
        return result;
    }

    private void waterDFS(boolean[][] ocean, int x, int y) {
        if (ocean[x][y]) return;
        ocean[x][y] = true;
        int fx, fy;
        for (int k = 0; k < 4; k++) {
            fx = x + dx[k];
            fy = y + dy[k];
            if (fx >= 0 && fx < m && fy >= 0 && fy < n && heights[x][y] <= heights[fx][fy])
                waterDFS(ocean, fx, fy);
        }
    }

}

17. 电话号码的字母组合

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public List<String> letterCombinations(String digits) {
        List<String> conbanations = new ArrayList<String>();
        if (digits.length() == 0) return conbanations;
        Map<Character, String> phoneMap = new HashMap<Character, String>() {{
            put('2', "abc");
            put('3', "def");
            put('4', "ghi");
            put('5', "jkl");
            put('6', "mno");
            put('7', "pqrs");
            put('8', "tuv");
            put('9', "wxyz");
        }};
        backtrack(conbanations, phoneMap, digits, 0, new StringBuffer());
        return conbanations;
    }

    private void backtrack(List<String> conbanations, Map<Character, String> phoneMap, String digits, int index, StringBuffer conbanation) {
        if (index == digits.length()) {
            conbanations.add(conbanation.toString());
            return;
        }
        Character digit = digits.charAt(index);
        String letters = phoneMap.get(digit);
        int letterCount = letters.length();
        for (int i = 0; i < letterCount; i++) {
            conbanation.append(letters.charAt(i));
            backtrack(conbanations, phoneMap, digits, index + 1, conbanation);
            conbanation.deleteCharAt(index);
        }
    }
}

93. 复原 IP 地址

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    List<String> Ips = new ArrayList<String>();
    List<String> store = new ArrayList<String>();
    public List<String> restoreIpAddresses(String s) {
        if (s.length() < 4 || s.length() > 12) return Ips;
        IpBacktrack(s, 0, 4);
        return Ips;
    }
    public void IpBacktrack(String s, int index, int num) {
        if (index == s.length() && num == 0) {  //没有剩余字符且刚好4段
            System.out.println(String.join(",", store));
            Ips.add(String.join(".", store));
            return;
        }
        if (s.length() < num + index || s.length() > 3 * num + index) return;   //每个ip段至多3位至少1位
        for (int i = 1; i <= 3; i++) {
            if (index + i <= s.length()) {
                String sub = s.substring(index, index + i);
                if (sub.charAt(0) == '0' && sub.length() > 1 || Integer.parseInt(sub) > 255) return;
                store.add(sub);
                IpBacktrack(s, index + i, num - 1);
                store.remove(4 - num);
            }
        }
    }
}

79. 单词搜索

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    int[] dx = new int[]{-1, 0, 0, 1};
    int[] dy = new int[]{0, 1, -1, 0};
    int m, n;
    boolean[][] used;    
    public boolean exist(char[][] board, String word) {
        this.m = board.length;
        this.n = board[0].length;
        if (word.length() > m * n) return false;

        this.used = new boolean[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++)
                if (board[i][j] == word.charAt(0) &&
                        existDFS(board, word, 0, i, j)) return true;
        }
        return false;
    }
    private boolean existDFS(char[][] board, String word, int index, int x, int y) {
        if (index == word.length()) return true;
        if (x < 0 || y < 0 || x == m || y == n || board[x][y] != word.charAt(index) || used[x][y] == true) return false;

        used[x][y] = true;
        for (int k = 0; k < 4; k++)
            if (existDFS(board, word, index + 1, x + dx[k], y + dy[k]))
                return true;
        
        used[x][y] = false;
        return false;
    }    
}

257. 二叉树的所有路径

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    List<String> store;
    List<String> treePaths;    
    public List<String> binaryTreePaths(TreeNode root) {
        treePaths = new ArrayList<String>();
        store = new ArrayList<String>();        
        treePathDFS(root, 0);
        return treePaths;
    }

    private void treePathDFS(TreeNode root, int level) {
        store.add(String.valueOf(root.val));
        if (root.left == null && root.right == null) treePaths.add(String.join("->", store));
        if (root.left != null) treePathDFS(root.left, level + 1);
        if (root.right != null) treePathDFS(root.right, level + 1);
        store.remove(level);
    }
}

46. 全排列

思路:注意result.add这行代码,需要将turn作为参数new一个对象
时间复杂度:O()
空间复杂度:O()

class Solution {
    List<List<Integer>> result;
    List<Integer> turn;
    boolean[] selected;
    public List<List<Integer>> permute(int[] nums) {
        int len = nums.length;
        selected = new boolean[len];
        result = new ArrayList<List<Integer>>();
        turn = new ArrayList<Integer>();
        for (int i = 0; i < nums.length; i++)
            permuterDFS(nums, i, 0);
        return result;
    }

    private void permuterDFS(int[] nums, int index, int level) {
        turn.add(nums[index]);
        selected[index] = true;
        if (level == nums.length - 1) result.add(new ArrayList<Integer>(turn));
        for (int i = 0; i < nums.length; i++)
            if (!selected[i]) permuterDFS(nums, i, level + 1);
        turn.remove(level);
        selected[index] = false;
    }
}

77. 组合

思路:组合不考虑顺序,i <= n - (k - level) + 1的作用是剪枝
时间复杂度:O()
空间复杂度:O()

class Solution {

    List<List<Integer>> result;
    List<Integer> turn;

    public List<List<Integer>> combine(int n, int k) {
        result = new ArrayList<List<Integer>>();
        turn = new ArrayList<Integer>();
        combineDFS(n, k, 0, 0);
        return result;
    }

    private void combineDFS(int n, int k, int num, int level) {
        if (level == k) {
            result.add(new ArrayList<Integer>(turn));
            return;
        }
        for (int i = num + 1; i <= n - (k - level) + 1; i++) {
            turn.add(i);
            combineDFS(n, k, i, level + 1);
            turn.remove(level);
        }
    }
}

思路
时间复杂度:O()
空间复杂度:O()


思路
时间复杂度:O()
空间复杂度:O()


思路
时间复杂度:O()
空间复杂度:O()


动态规划

70. 爬楼梯

思路:动态规划,f(x)=f(x−1)+f(x−2)
时间复杂度:O(N)
空间复杂度:O(1)

class Solution {
    public int climbStairs(int n) {
        int one = 0, two = 0, result = 1;
        for (int i = 1; i <= n; i++) {
            one = two;
            two = result;
            result = one + two;
        }
        return result;
    }
}

198. 打家劫舍

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public int rob(int[] nums) {
        int prev = 0, curr = 0;
        for (int i : nums) {
            int turn = Math.max(prev + i, curr);
            prev = curr;
            curr = turn;
        }
        return curr;
    }
}

213. 打家劫舍 II

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public int rob(int[] nums) {
        int len = nums.length;
        return Math.max(nums[0] + robDirect(nums, 2, len - 1), robDirect(nums, 1, len));
    }
    private int robDirect(int[] nums, int start, int end) {
        int prev = 0, curr = 0;
        for (int i = start; i < end; i++) {
            int turn = Math.max(prev + nums[i], curr);
            prev = curr;
            curr = turn;
        }
        return curr;
    }
}

64. 最小路径和

思路:从左到右,从上往下
时间复杂度:O(M*N)
空间复杂度:O(1)

class Solution {
    public int minPathSum(int[][] grid) {
        int row = grid.length, column = grid[0].length;
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                if (0 == i && 0 == j) continue;
                else if (0 == i) grid[i][j] = grid[i][j - 1] + grid[i][j];
                else if (0 == j) grid[i][j] = grid[i - 1][j] + grid[i][j];
                else grid[i][j] = Math.min(grid[i][j - 1], grid[i - 1][j]) + grid[i][j];
            }
        }
        return grid[row - 1][column - 1];
    }
}

62. 不同路径

思路:不需要M*N的空间,交换m和n不影响结果,空间只需要min(m,n),答案没有体现这一点
时间复杂度:O(M*N)
空间复杂度:O(min(M,N))

解法一:
class Solution {
    public int uniquePaths(int m, int n) {
        int[] grid = new int[n];
        Arrays.fill(grid, 1);
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                grid[j] += grid[j - 1];
            }
        }
        return grid[n - 1];
    }
}

思路:组合计算,从总移动次数中取出t-1次向下【t=min(m,n)】

在这里插入图片描述

时间复杂度:O(min(m,n))
空间复杂度:O(1)

解法二:
class Solution {
    public int uniquePaths(int m, int n) {
        int t = Math.min(m, n); //向下移动次数,用min减少计算次数
        int k = Math.max(m, n);
        long result = 1; // 防止溢出
        for (int x = k, y = 1; y < t; x++, y++) result = result * x / y; //经过推导,减少计算次数
        return (int) result;
    }
}

303. 区域和检索 - 数组不可变

思路:如果多次调用sumRange,存在大量重复计算,采用前缀和,空间换时间
时间复杂度:初始化O(N)、单次sumRangeO(1)
空间复杂度:O(N)

class NumArray {

    int[] sums;

    public NumArray(int[] nums) {
        int len = nums.length;
        sums = new int[len + 1];
        for (int i = 0; i < len; i++) sums[i + 1] = nums[i] + sums[i];
    }

    public int sumRange(int left, int right) {
        return sums[right + 1] - sums[left];
    }
}

413. 等差数列划分

思路
时间复杂度:O(N)
空间复杂度:O(N)

class Solution {
    public int numberOfArithmeticSlices(int[] nums) {
        if (nums.length < 3) return 0;

        int len = nums.length;
        int[] dps = new int[len];

        for (int i = 2; i < len; i++)
            if (nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2])
                dps[i] = dps[i - 1] + 1;
        
        int result=0;
        for(int i:dps) result+=i;
        
        return result;
    }
}

343. 整数拆分

思路:当f >= 4,2(f-2)=2f-4>=f,所以不需要>=4的因子
时间复杂度:O(1)
空间复杂度:O(1)

class Solution {
    public int integerBreak(int n) {
        if (n <= 3) return 1 * (n - 1);
        int a = n / 3, b = n % 3;
        int result = 1;
        for (int i = 1; i < a; i++) result *= 3;
        if (b == 1) return 4 * result;
        else if (b == 2) return 6 * result;
        else return 3 * result;
    }
}

279. 完全平方数

思路:参考四平方定理
时间复杂度:O(√N)
空间复杂度:O()

class Solution {
    public int numSquares(int n) {
        if (isPerfectSquare(n)) return 1;
        else if (checkAnswer4(n)) return 4;
        for (int i = 1; i * i < n; i++) {
            int j = n - i * i;
            if (isPerfectSquare(j)) return 2;
        }
        return 3;
    }

    private boolean checkAnswer4(int n) {
        while (n % 4 == 0) n /= 4;
        return n % 8 == 7;
    }

    private boolean isPerfectSquare(int n) {
        int x = (int) Math.sqrt(n);
        return x * x == n;
    }
}

300. 最长递增子序列

思路:动态规划
时间复杂度:O(N²)
空间复杂度:O(N)

解法一:
class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length];
        int result = 1;
        for (int i = 0; i < nums.length; i++) {
            dp[i] = 1;
            for (int j = 0; j < i; j++)
                if (nums[i] > nums[j])
                    dp[i] = Math.max(dp[i], dp[j] + 1);
            result = Math.max(result, dp[i]);
        }
        return result;
    }
}

思路:贪心+二分查找,要使上升子序列尽可能长,则序列上升得尽可能慢,因此每次在上升子序列最后加上的数尽可能的小。
时间复杂度:O(NlogN)
空间复杂度:O(N)

解法二:
class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int len = 0;
        for (int i = 0; i < nums.length; i++) {
            if (dp[len] < nums[i]) dp[++len] = nums[i];
            else if (dp[0] > nums[i]) dp[0] = nums[i];
            else {
                //二分查找,找到dp中第一个大于等于nums[i]的元素,替换这个元素
                int left = 0, right = len;
                while (left < right) {
                    int mid = (left + right) >> 1;
                    if (dp[mid] < nums[i]) left = mid + 1;
                    else right = mid;
                }
                dp[left] = nums[i];
            }
        }
        return len + 1;
    }
}

646. 最长数对链

思路
时间复杂度:O()
空间复杂度:O()


思路
时间复杂度:O()
空间复杂度:O()


二分查找

我在做这类型题目的时候,解题思路是一部分,
另一部分卡在循环判断【left < right 还是 left <= right】
、左右边界修改[left 和 right 如何利用 mid 修改边界,才不会导致死循环或者溢出]
每道题都需要具体的判断,暂时是通过画图解决,
会有特殊处理,例如数组仅包含 0 或者 1 个元素

69. x 的平方根

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public int mySqrt(int x) {
        if (x <= 1) return x;
        int left = 1, right = x / 2;
        while (left < right) {
            int mid = left + (right - left + 1) / 2;
            if (mid == x / mid) return mid;
            else if (mid < x / mid) left = mid;
            else right = mid - 1;
        }
        return left;
    }
}

744. 寻找比目标字母大的最小字母

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public char nextGreatestLetter(char[] letters, char target) {
        int len = letters.length;
        if (letters[len - 1] <= target || letters[0] > target) return letters[0];
        int left = 0, right = len - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (letters[mid] <= target) left = mid + 1;
            else right = mid;
        }
        return letters[right] > target ? letters[right] : letters[0];
    }
}

540. 有序数组中的单一元素

思路
时间复杂度:O()
空间复杂度:O()

解法一:
class Solution {
    public int singleNonDuplicate(int[] nums) {
        int ans = 0;
        for (int i : nums) ans ^= i;
        return ans;
    }
}
解法二:
class Solution {
    public int singleNonDuplicate(int[] nums) {
        int low = 0, high = nums.length - 1;
        while (low < high) {
            int mid = low + (high - low) / 2;
            if (nums[mid] == nums[mid ^ 1]) low = mid + 1;
            else high = mid;
        }
        return nums[low];
    }
}

278. 第一个错误的版本

思路
时间复杂度:O()
空间复杂度:O()

/* The isBadVersion API is defined in the parent class VersionControl.
      boolean isBadVersion(int version); */

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int left = 1, right = n;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (isBadVersion(mid)) right = mid;
            else left = mid + 1;
        }
        return left;
    }
}

153. 寻找旋转排序数组中的最小值

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public int findMin(int[] nums) {
        int left = 0, right = nums.length - 1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < nums[right]) right = mid;
            else left = mid + 1;
        }
        return nums[left];
    }
}

34. 在排序数组中查找元素的第一个和最后一个位置

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public int[] searchRange(int[] nums, int target) {
        if (nums.length == 0) return new int[]{-1, -1};
        int left = findleft(nums, target);
        int right = findright(nums, target);
        return new int[]{left, right};
    }

    // 找第一个等于target的index
    private int findleft(int[] nums, int target) {
        int left = 0, right = nums.length - 1, result = -1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                result = mid;
                right = mid - 1;
            } else if (nums[mid] > target) right = mid - 1;
            else left = mid + 1;
        }
        return result;
    }

    // 找最后一个等于target的index
    private int findright(int[] nums, int target) {
        int left = 0, right = nums.length - 1, result = -1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                result = mid;
                left = mid + 1;
            } else if (nums[mid] > target) right = mid - 1;
            else left = mid + 1;
        }
        return result;
    }
}

贪心思想

思路
时间复杂度:O()
空间复杂度:O()


双指针

167. 两数之和 II - 输入有序数组

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int l = 0, r = numbers.length - 1;
        while (l < r) {
            if (numbers[l] + numbers[r] < target) l++;
            else if (numbers[l] + numbers[r] > target) r--;
            else break;
        }
        return new int[]{l + 1, r + 1};
    }
}

633. 平方数之和

思路:不可以二分: mid = l + r / 2,z = x * x + y * y是抛物面
时间复杂度:O()
空间复杂度:O()

class Solution {
    public boolean judgeSquareSum(int c) {
        long r = (int) Math.sqrt(c), l = 0;
        long Square;
        while (l <= r) {
            Square = l * l + r * r;
            if (Square == c) return true;
            else if (Square < c) l++;
            else if (Square > c) r--;
        }
        return false;
    }
}

345. 反转字符串中的元音字母

思路
时间复杂度:O(N)
空间复杂度:O(N)

class Solution {
    private final static HashSet<Character> vowels = new HashSet<>(
            Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));

    public String reverseVowels(String s) {
        char[] cs = s.toCharArray();
        int l = 0, r = cs.length - 1, n = cs.length;
        while (l < r) {
            while (l < n && !vowels.contains(cs[l]))
                l++;
            while (r > 0 && !vowels.contains(cs[r]))
                r--;
            if (l < r) {
                char turn = cs[l];
                cs[l] = cs[r];
                cs[r] = turn;
                l++;
                r--;
            }
        }
        return new String(cs);
    }
}

680. 验证回文串 II

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    boolean deleted = false;
    public boolean validPalindrome(String s) {
        char[] arr = s.toCharArray();
        int l = 0, r = arr.length - 1;
        while (l < r) {
            if (arr[l] == arr[r]) {
                l++;
                r--;
            } else return isPalindrome(s.substring(l, r)) || isPalindrome(s.substring(l + 1, r + 1));
        }
        return true;
    }
    private boolean isPalindrome(String s) {
        char[] arr = s.toCharArray();
        int l = 0, r = arr.length - 1;
        while (l < r) {
            if (arr[l] == arr[r]) {
                l++;
                r--;
            } else return false;
        }
        return true;
    }
}

88. 合并两个有序数组

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        if (0 == n) return;
        if (0 == m) {
            for (int i = 0; i < n; i++) nums1[i] = nums2[i];
            return;
        }
        int tail = m + n - 1;
        m--;
        n--;
        while (n >= 0) {
            if (m >= 0 && nums1[m] >= nums2[n]) nums1[tail--] = nums1[m--];
            else nums1[tail--] = nums2[n--];
        }
    }
}

141. 环形链表

思路
时间复杂度:O()
空间复杂度:O()

public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null)
            return false;
        ListNode slow = head, fast = head.next;
        while (slow != fast) {
            if (fast == null || fast.next == null)
                return false;
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    }
}

524. 通过删除字母匹配到字典里最长单词

思路:先排序,后证明子字符串
时间复杂度:O()
空间复杂度:O()

class Solution {
    public String findLongestWord(String s, List<String> dictionary) {
        Collections.sort(dictionary, (a, b) -> {
            if (a.length() != b.length()) return b.length() - a.length();  // 降序
            else return a.compareTo(b);  //升序
        });
        for (String elem : dictionary) {
            int i = 0, j = 0, len1 = s.length(), len2 = elem.length();
            while (i < len1 && j < len2) {
                if (s.charAt(i) == elem.charAt(j)) j++;
                i++;
            }
            if (j == len2) return elem;
        }
        return "";
    }
}

思路
时间复杂度:O()
空间复杂度:O()


104. 二叉树的最大深度

思路
时间复杂度:O(n)
空间复杂度:O(1)

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

110. 平衡二叉树

思路
时间复杂度:O(N)
空间复杂度:O(N)

class Solution {
    public boolean isBalanced(TreeNode root) {
        return recur(root) >= 0;
    }

    private int recur(TreeNode root) {
        if (null == root) return 0;
        int left = recur(root.left);
        if (left == -1) return -1;
        int right = recur(root.right);
        if (right == -1) return -1;
        return Math.abs(left - right) < 2 ? Math.max(left, right) + 1 : -1;
    }
}

543. 二叉树的直径

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    int max = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        depth(root);
        return max;
    }

    private int depth(TreeNode root) {
        if (null == root) return 0;
        int left = depth(root.left);
        int right = depth(root.right);
        max = Math.max(max, left + right);
        return Math.max(left, right) + 1;
    }
}

226. 翻转二叉树

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if (null == root) return root;
        TreeNode turn = root.left;
        root.left = root.right;
        root.right = turn;
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
}

617. 合并二叉树

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if (null == root1) return root2;
        if (null == root2) return root1;
        root1.val += root2.val;
        root1.left = mergeTrees(root1.left, root2.left);
        root1.right = mergeTrees(root1.right, root2.right);
        return root1;
    }
}

112. 路径总和

思路
时间复杂度:O(N)
空间复杂度:O(height)

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if (null == root) return false;
        if (null != root.left || null != root.right)
            return hasPathSum(root.left, targetSum - root.val)
                    || hasPathSum(root.right, targetSum - root.val);
        return targetSum == root.val;
    }
}

437. 路径总和 III

思路
时间复杂度:O(1)
空间复杂度:O(1)

解法一:
class Solution {
    int ans = 0;
    public int pathSum(TreeNode root, int targetSum) {
        allPath(root, targetSum);
        return ans;
    }
    private void allPath(TreeNode root, int targetSum) {
        if (null == root) return;
        findPath(root, targetSum);
        allPath(root.left, targetSum);
        allPath(root.right, targetSum);
    }
    private void findPath(TreeNode root, long targetSum) {
        if (null == root) return;
        if (root.val == targetSum) ans++;
        findPath(root.left, targetSum - root.val);
        findPath(root.right, targetSum - root.val);
    }
}
解法二:
class Solution {
    int t, ans;
    Map<Long, Integer> map = new HashMap<>();
    public int pathSum(TreeNode root, int targetSum) {
        if (null == root) return 0;
        t = targetSum;
        map.put(0L, 1);
        dfs(root, root.val);
        return ans;
    }
    void dfs(TreeNode root, long val) {
        if (map.containsKey(val - t)) ans += map.get(val - t);
        map.put(val, map.getOrDefault(val, 0) + 1);
        if (null != root.left) dfs(root.left, val + root.left.val);
        if (null != root.right) dfs(root.right, val + root.right.val);
        map.put(val, map.getOrDefault(val, 0) - 1);
    }
}

572. 另一棵树的子树

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if (null == root && null == subRoot) return true;
        if (null == root || null == subRoot) return false;
        return isSametree(root, subRoot) || isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
    }
    private boolean isSametree(TreeNode t1, TreeNode t2) {
        if (null == t1 && null == t2) return true;
        if (null == t1 || null == t2) return false;
        return t1.val == t2.val && isSametree(t1.left, t2.left) && isSametree(t1.right, t2.right);
    }
}

101. 对称二叉树

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return check(root, root);
    }
    private boolean check(TreeNode p, TreeNode q) {
        if (null == p && null == q) return true;
        if (null == p || null == q) return false;
        return p.val == q.val && check(p.left, q.right) && check(p.right, q.left);
    }    
}

111. 二叉树的最小深度

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int minDepth(TreeNode root) {
        if (null == root) return 0;
        int m1 = minDepth(root.left);
        int m2 = minDepth(root.right);
        return null == root.right || null == root.left ? m1 + m2 + 1 : Math.min(m1, m2) + 1;
    }
}

404. 左叶子之和

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        if (null == root) return 0;
        if (null != root.left && null == root.left.left && null == root.left.right)
            return root.left.val + sumOfLeftLeaves(root.right);
        return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
    }
}

687. 最长同值路径

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    int ans;
    public int longestUnivaluePath(TreeNode root) {
        ans = 0;
        maxSingleLine(root);
        return ans;
    }
    private int maxSingleLine(TreeNode root) {
        if (null == root) return 0;
        int left = maxSingleLine(root.left), left1 = 0;
        int right = maxSingleLine(root.right), right1 = 0;
        if (null != root.left && root.val == root.left.val) left1 = left + 1;
        if (null != root.right && root.val == root.right.val) right1 = right + 1;
        ans = Math.max(ans, left1 + right1);
        return Math.max(left1, right1);
    }
}

337. 打家劫舍 III

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int rob(TreeNode root) {
        int[] result = robDfs(root);
        return Math.max(result[0], result[1]);
    }
    private int[] robDfs(TreeNode root) {
        if (null == root) return new int[2];
        int[] l = robDfs(root.left);
        int[] r = robDfs(root.right);
        int selected = root.val + l[1] + r[1];
        int nonselected = Math.max(l[0], l[1]) + Math.max(r[0], r[1]);
        return new int[]{selected, nonselected};
    }
}

671. 二叉树中第二小的节点

思路
时间复杂度:O(N)
空间复杂度:O(N)

class Solution {
    int ans, t;
    public int findSecondMinimumValue(TreeNode root) {
        ans = -1;
        t = root.val;
        secondDfs(root);
        return ans;
    }
    private void secondDfs(TreeNode root) {
        if (null == root) return;
        if (-1 != ans && root.val >= ans) return;
        if (root.val > t) {
            ans = root.val;
            return;
        }
        secondDfs(root.left);
        secondDfs(root.right);
    }
}

637. 二叉树的层平均值

思路
时间复杂度:O(N)
空间复杂度:O(1)

class Solution {
    public List<Double> averageOfLevels(TreeNode root) {
        List<Double> averages = new ArrayList<Double>();
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            double sum = 0;
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode t = queue.poll();
                sum += t.val;
                if (null != t.left) queue.offer(t.left);
                if (null != t.right) queue.offer(t.right);
            }
            averages.add(sum / size);
        }
        return averages;
    }
}

513. 找树左下角的值

思路
时间复杂度:O(N)
空间复杂度:O(1)

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        int ans = 0;
        queue.offer(root);
        while (!queue.isEmpty()) {
            int sz = queue.size();
            ans = queue.peek().val;
            while (sz-- > 0) {
                TreeNode t = queue.poll();
                if (null != t.left) queue.offer(t.left);
                if (null != t.right) queue.offer(t.right);
            }
        }
        return ans;
    }
}

144. 二叉树的前序遍历

思路:前中后序只是顺序不同,分别有递归、迭代、Morris 遍历三种解法
时间复杂度:O(N)
空间复杂度:O(N)

递归解法
class Solution {
    List<Integer> res = new ArrayList<Integer>();    
    public List<Integer> preorderTraversal(TreeNode root) {
        preorder(root);
        return res;
    }
    private void preorder(TreeNode root) {
        if (null == root) return;
        res.add(root.val);
        preorder(root.left);
        preorder(root.right);
    }
}

145. 二叉树的后序遍历

思路:迭代即使用显式的栈来存储遍历过程中的节点信息
时间复杂度:O(N)
空间复杂度:O(N)

递归解法
class Solution {
    List<Integer> res = new ArrayList<Integer>();
    public List<Integer> postorderTraversal(TreeNode root) {
        postorder(root);
        return res;
    }
    private void postorder(TreeNode root) {
        if (null == root) return;
        postorder(root.left);
        postorder(root.right);
        res.add(root.val);
    }
}

94. 二叉树的中序遍历

思路
时间复杂度:O(N)
空间复杂度:O(1)

递归解法
class Solution {
    List<Integer> res = new ArrayList<Integer>();
    public List<Integer> inorderTraversal(TreeNode root) {
        inorder(root);
        return res;
    }
    private void inorder(TreeNode root) {
        if (null == root) return;
        inorder(root.left);
        res.add(root.val);
        inorder(root.right);
    }
}

669. 修剪二叉搜索树

思路
时间复杂度:O(N)
空间复杂度:O(N)

class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (null == root) return root;
        if (root.val < low) return trimBST(root.right, low, high);
        if (root.val > high) return trimBST(root.left, low, high);
        root.left = trimBST(root.left, low, high);
        root.right = trimBST(root.right, low, high);
        return root;
    }
}

230. 二叉搜索树中第K小的元素

思路
时间复杂度:O(N)
空间复杂度:O(1)

class Solution {
    public int kthSmallest(TreeNode root, int k) {
        Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
        while (null != root || !stack.isEmpty()) {
            while (null != root) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            k--;
            if (0 == k) break;
            root = root.right;
        }
        return root.val;
    }
}

538. 把二叉搜索树转换为累加树

思路
时间复杂度:O(N)
空间复杂度:O(N)

解法一 DFS
class Solution {
    int sum = 0;
    public TreeNode convertBST(TreeNode root) {
        if (null != root) {
            convertBST(root.right);
            sum += root.val;
            root.val = sum;
            convertBST(root.left);
        }
        return root;
    }
}
解法二 BFS
class Solution {
    public TreeNode convertBST(TreeNode root) {
        Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
        TreeNode t = root;
        int n = 0;
        while (null != t || !stack.isEmpty()) {
            while (null != t) {
                stack.push(t);
                t = t.right;
            }
            t = stack.pop();
            t.val += n;
            n = t.val;
            t = t.left;
        }
        return root;
    }
}

235. 二叉搜索树的最近公共祖先

思路
时间复杂度:O(N)
空间复杂度:O(1)

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        TreeNode t = root;
        while (true) {
            if (p.val < t.val && q.val < t.val)
                t = t.left;
            else if (p.val > t.val && q.val > t.val)
                t = t.right;
            else
                break;
        }
        return t;
    }
}

236. 二叉树的最近公共祖先

思路
时间复杂度:O(N)
空间复杂度:O(1)

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (null == root || p == root || q == root) return root;

        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);

        if (null != left && null != right) return root;
        return null != left ? left : right;
    }
}

108. 将有序数组转换为二叉搜索树

思路
时间复杂度:O(N)
空间复杂度:O(H)

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return helper(nums, 0, nums.length - 1);
    }

    private TreeNode helper(int[] nums, int left, int right) {
        if (left > right) return null;
        int mid = (left + right) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = helper(nums, left, mid - 1);
        root.right = helper(nums, mid + 1, right);
        return root;
    }
}

653. 两数之和 IV - 输入二叉搜索树

思路
时间复杂度:O(N)
空间复杂度:O(1)

class Solution {
    Set<Integer> set = new HashSet<Integer>();
    public boolean findTarget(TreeNode root, int k) {
        if (null == root) return false;
        if (set.contains(k - root.val)) return true;
        set.add(root.val);
        return findTarget(root.left, k) || findTarget(root.right, k);
    }
}

思路
时间复杂度:O(N)
空间复杂度:O(1)


链表

160. 相交链表

思路
时间复杂度:O()
空间复杂度:O()

解法一
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return null;
        ListNode pA = headA, pB = headB;
        while (pA != pB) {
            pA = pA == null ? headB : pA.next;
            pB = pB == null ? headA : pB.next;
        }
        return pA;
    }
}
解法二
用哈希表存储第一条单链表每个节点,第二次遍历另一条单链表每个节点是否存在于哈希表中

206. 反转链表

思路
时间复杂度:O(N)
空间复杂度:O(1)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode curr = head, prev = null;
        while (curr != null) {
            ListNode next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
}

21. 合并两个有序链表

思路
时间复杂度:O()
空间复杂度:O()

解法一:迭代
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode head = new ListNode(-1);
        ListNode prev = head;
        while (null != l1 && null != l2) {
            if (l1.val <= l2.val) {
                prev.next = l1;
                l1 = l1.next;
            } else {
                prev.next = l2;
                l2 = l2.next;
            }
            prev = prev.next;
        }
        prev.next = l1 == null ? l2 : l1;
        return head.next;
    }
}
解法二:递归

83. 删除排序链表中的重复元素

思路:代码可以精简一下,不需要prev
时间复杂度:O(N)
空间复杂度:O(1)

解法一:
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if (null == head) return head;
        ListNode curr = head;
        ListNode prev = head.next;
        while (null != curr.next) {
            if (curr.val == prev.val) {
                curr.next = prev.next;
                prev = curr.next;
            } else {
                curr = curr.next;
                prev = prev.next;
            }
        }
        return head;
    }
}
解法二:

19. 删除链表的倒数第 N 个结点

思路
时间复杂度:O()
空间复杂度:O()

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0, head);
        int len = getLength(head);
        ListNode curr = dummy;
        for (int i = 0; i < len - n; i++) curr = curr.next;
        curr.next = curr.next.next;
        return dummy.next;
   }
       public int getLength(ListNode head) {
        int num = 0;
        while (null != head) {
            num++;
            head = head.next;
        }
        return num;
    }
}

24. 两两交换链表中的节点

思路
时间复杂度:O(N)
空间复杂度:O(N)

class Solution {
    public ListNode swapPairs(ListNode head) {
        if (null == head || null == head.next) return head;
        ListNode newhead = head.next;
        head.next = swapPairs(newhead.next);
        newhead.next = head;
        return newhead;
    }
}

445. 两数相加 II

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Deque<Integer> stack1 = new ArrayDeque<Integer>();
        Deque<Integer> stack2 = new ArrayDeque<Integer>();
        while (null != l1) {
            stack1.push(l1.val);
            l1 = l1.next;
        }
        while (null != l2) {
            stack2.push(l2.val);
            l2 = l2.next;
        }
        int carry = 0;
        ListNode ans = null;
        while (!stack1.isEmpty() || !stack2.isEmpty() || 0 != carry) {
            int a = stack1.isEmpty() ? 0 : stack1.pop();
            int b = stack2.isEmpty() ? 0 : stack2.pop();
            int cur = a + b + carry;
            carry = cur / 10;
            cur = cur % 10;
            ListNode node = new ListNode(cur);
            node.next = ans;
            ans = node;
        }
        return ans;
    }
}

234. 回文链表

思路
时间复杂度:O()
空间复杂度:O()

class Solution {
    public boolean isPalindrome(ListNode head) {
        ListNode slow = endOfFirstHalt(head);
        ListNode reserve = reverse(slow.next);
        ListNode turn = reserve;
        slow = head;
        while (reserve != null) {
            if (reserve.val != slow.val) {
                reverse(reserve);
                return false;
            }
            slow=slow.next;
            reserve=reserve.next;
        }
        reverse(reserve);
        return true;
    }
    // 234的反转函数
    private ListNode reverse(ListNode head) {
        ListNode prev = null, curr = head, next = null;
        while (curr != null) {
            next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }

    // 234的找中点函数
    private ListNode endOfFirstHalt(ListNode head) {
        ListNode slow = head, fast = head;
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }
}

725. 分隔链表

思路
时间复杂度:O()
空间复杂度:O()

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode[] splitListToParts(ListNode head, int k) {
        int len = getLength(head);
        int remainder = len % k;
        int quotient = len / k;
        ListNode[] result = new ListNode[k];
        if (quotient > 0) {
            for (int i = 0; i < remainder; i++) {
                result[i] = head;
                for (int j = 0; j < quotient; j++) head = head.next;
                ListNode turn = head.next;
                head.next = null;
                head = turn;
            }
            for (int i = remainder; i < k; i++) {
                result[i] = head;
                for (int j = 0; j < quotient - 1; j++) head = head.next;
                ListNode turn = head.next;
                head.next = null;
                head = turn;
            }
        } else {
            for (int i = 0; i < remainder; i++) {
                result[i] = head;
                ListNode turn = head.next;
                head.next = null;
                head = turn;
            }
        }
        return result;
    }
    private int getLength(ListNode head) {
        int num = 0;
        while (null != head) {
            num++;
            head = head.next;
        }
        return num;
    }
}

328. 奇偶链表

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public ListNode oddEvenList(ListNode head) {
        if (null == head) return head;
        ListNode odd = head;
        ListNode evenhead = head.next, even = head.next;
        while (null != even && null != even.next) {
            odd.next = even.next;
            odd = odd.next;
            even.next = odd.next;
            even = even.next;
        }
        odd.next = evenhead;
        return head;
    }
}

思路
时间复杂度:O(n)
空间复杂度:O(1)


数组与矩阵

283. 移动零

思路:双指针
时间复杂度:O(N)
空间复杂度:O(1)

class Solution {
    public void moveZeroes(int[] nums) {
          if (nums == null) {
            return;
        }
        int j = 0;
        for (int i = 0; i < nums.length; i++) {
            if (0 != nums[i]) {
                nums[j++] = nums[i];
            }
        }
        for (; j < nums.length; j++) {
            nums[j] = 0;
        }
    }
}

566. 重塑矩阵

思路:逐一映射,flatten
时间复杂度:O(mn)
空间复杂度:O(1)

class Solution {
    public int[][] matrixReshape(int[][] mat, int r, int c) {
             int m = mat.length;
        int n = mat[0].length;
        if (m * n != r * c) return mat;
        int[][] ans = new int[r][c];
        int ri = 0, cj = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                ans[ri][cj++] = mat[i][j];
                if (cj == c) {
                    ri++;
                    cj=0;
                }
            }
        }
        return ans;
    }
}

485. 最大连续 1 的个数

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int findMaxConsecutiveOnes(int[] nums) {
        int n = nums.length;
        int maxCount = 0, count = 0;
        for (int i = 0; i < n; i++) {
            if (1 == nums[i]) {
                count++;
            } else {
                maxCount = Math.max(maxCount, count);
                count = 0;
            }
        }
        maxCount = Math.max(maxCount, count);
        return maxCount;
    }
}

240. 搜索二维矩阵 II

思路

  1. 每行最后元素较小,整行舍弃。剩余行二分查找
  2. 从右上角二分查找,向左变小,向下变大【采用】
    时间复杂度:O(m+n)
    空间复杂度:O(1)
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
                int m = 0, n = matrix[0].length - 1;
        while (m < matrix.length && n >= 0) {
            if (target < matrix[m][n]) {
                n--;
            } else if (target > matrix[m][n]) {
                m++;
            } else {
                return true;
            }
        }
        return false;
    }
}

378. 有序矩阵中第 K 小的元素

思路
时间复杂度:O(n)
空间复杂度:O(1)


645. 错误的集合

思路
时间复杂度:O(n)
空间复杂度:O(1)

287. 寻找重复数

思路
时间复杂度:O(n)
空间复杂度:O(1)

. 模板

思路
时间复杂度:O(n)
空间复杂度:O(1)


栈和队列

232. 用栈实现队列

思路:双指针
时间复杂度:O(N)
空间复杂度:O(1)


. 模板

思路
时间复杂度:O(n)
空间复杂度:O(1)


字符串

242. 有效的字母异位词

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length()) return false;
        int[] record = new int[26];
        for (char i : s.toCharArray()) {
            record[i - 'a'] += 1;
        }
        for (char j : t.toCharArray()) {
            record[j - 'a'] -= 1;
        }
        for (int k : record) {
            if (k != 0) return false;
        }
        return true;
    }
}

409. 最长回文串

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int longestPalindrome(String s) {
        int[] record = new int[128];
        for (char c : s.toCharArray()) record[c]++;
        int ans = 0;
        for (int i : record) {
            ans += 2 * (i / 2);
            if (i % 2 == 1 && ans % 2 == 00) ans++;
        }
        return ans;
    }
}

205. 同构字符串

思路
时间复杂度:O(n)
空间复杂度:O(1)

解法一:
class Solution {
    public boolean isIsomorphic(String s, String t) {
        return isIsomorphicHelper(s, t) && isIsomorphicHelper(t, s);
    }

        private boolean isIsomorphicHelper(String s, String t) {
        if (s.length() != t.length()) return false;
        HashMap<Character, Character> record = new HashMap<Character, Character>();
        int len = s.length();
        for (int i = 0; i < len; i++) {
            char S = s.charAt(i);
            char T = t.charAt(i);
            if (record.containsKey(S)) {
                if (record.get(S) != T) return false;
            } else {
                record.put(S, T);
            }
        }
        return true;
    }
}
解法二:
class Solution {
    public boolean isIsomorphic(String s, String t) {
        if (s.length() != t.length()) return false;
        int[] S = new int[128];
        int[] T = new int[128];
        for (int i = 0; i < s.length(); i++) {
            char cs = s.charAt(i);
            char ct = t.charAt(i);
            if (S[cs] == T[ct]) S[cs] = T[ct] = i + 1;
            else return false;
        }
        return true;
    }
}

647. 回文子串

思路
时间复杂度:O(n)
空间复杂度:O(1)


9. 回文数

思路
时间复杂度:O(n)
空间复杂度:O(n)

解法一:
class Solution {
    public boolean isPalindrome(int x) {
        if (x < 0) return false;
        String record = Integer.toString(x);
        StringBuilder reverse = new StringBuilder(record).reverse();
        return record.equals(reverse.toString());
    }
}

696. 计数二进制子串

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int countBinarySubstrings(String s) {
        List<Integer> record = new ArrayList<Integer>();
        char[] S = s.toCharArray();
        int count = 1;
        char t = S[0];
        for (int i = 1; i < S.length; i++) {
            if (t != S[i]) {
                t = S[i];
                record.add(count);
                count = 1;
            } else count++;
        }
        record.add(count);
        int ans = 0;
        for (int i = 0; i < record.size() - 1; i++) {
            ans += Math.min(record.get(i), record.get(i + 1));
        }
        return ans;
    }
}

位运算

461. 汉明距离

思路
时间复杂度:O(1)
空间复杂度:O(1)

class Solution {
    public int hammingDistance(int x, int y) {
        return Integer.bitCount(x ^ y);
    }
}

136. 只出现一次的数字

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int singleNumber(int[] nums) {
        int j = 0;
        for (int i : nums) {
            j = j ^ i;
        }
        return j;
    }
}

268. 丢失的数字

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int missingNumber(int[] nums) {
        int n = nums.length;
        int xor = 0;
        for (int i = 0; i <= n; i++) {
            xor ^= i;
        }
        for (int i = 0; i < n; i++) {
            xor ^= nums[i];
        }
        return xor;
    }
}

260. 只出现一次的数字 III

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int[] singleNumber(int[] nums) {
        int xor = 0;
        for (int num : nums) xor ^= num;
        int lsb = (xor == Integer.MIN_VALUE ? xor : xor & (-xor));
        int num1 = 0, num2 = 0;
        for (int num : nums) {
            if ((num & lsb) != 0) num1 ^= num;
            else num2 ^= num;
        }
        return new int[]{num1, num2};
    }
}

190. 颠倒二进制位

思路
时间复杂度:O(n)
空间复杂度:O(1)

public class Solution {
    // you need treat n as an unsigned value
    public int reverseBits(int n) {
        int record = 0;
        for (int i = 0; i < 32 & n != 0; i++) {
            record |= (n & 1) << (31 - i);
            n >>>= 1;
        }
        return record;
    }
}

231. 2 的幂

思路
时间复杂度:O(1)
空间复杂度:O(1)

解法一:
class Solution {
    public boolean isPowerOfTwo(int n) {
        return n > 0 && 0 == (n & (n - 1));    
    }
}
解法二:
class Solution {
    public boolean isPowerOfTwo(int n) {
        return n > 0 && n == (n & (-n));    
    }
}

342. 4的幂

思路
时间复杂度:O(n)
空间复杂度:O(1)

解法一:
class Solution {
    public boolean isPowerOfFour(int n) {
        return n > 0 && n == (n & (-n)) && (n & 0xaaaaaaaa) == 0;
    }
}
解法二:
class Solution {
    public boolean isPowerOfFour(int n) {
        return n > 0 && n == (n & (-n)) && n % 3 == 1;
    }
}

693. 交替位二进制数

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public boolean hasAlternatingBits(int n) {
        int a = n ^ (n >> 1);
        return 0 == (a & (a + 1));
    }
}

476. 数字的补数

思路
时间复杂度:O(n)
空间复杂度:O(1)

解法一:
class Solution {
    public int findComplement(int num) {
        long turn = 1;
        while (turn <= num) {
            turn = turn << 1;
        }
        return (int) (turn - 1) ^ num;
    }
}
解法二:
class Solution {
    public int findComplement(int num) {
        int x = 0;
        for (int i = num; i > 0; i -= i & (-i)) x = i;
        return (x - 1) & ~num;
    }
}

371. 两整数之和

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int getSum(int a, int b) {
        while (b != 0) {
            int turn = (a & b) << 1;
            a = a ^ b;
            b = turn;
        }
        return a;
    }
}

318. 最大单词长度乘积

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int maxProduct(String[] words) {
        int len = words.length, index = 0;
        int[] masks = new int[len];
        for (String word : words) {
            int t = 0;
            for (int i = 0; i < word.length(); i++) {
                int u = word.charAt(i) - 'a';
                t |= (1 << u);
            }
            masks[index++] = t;
        }
        int ans = 0;
        for (int i = 0; i < len; i++) {
            for (int j = 0; j < i; j++) {
                if ((masks[i] & masks[j]) == 0) ans = Math.max(ans, words[i].length() * words[j].length());
            }
        }
        return ans;
    }
}

338. 比特位计数

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int[] countBits(int n) {
        int[] record = new int[n + 1];
        record[0] = 0;
        for (int i = 1; i <= n; i++) {
            if (0 == i % 2) {
                record[i] = record[i / 2];

            } else if (1 == i % 2) {
                record[i] = record[i - 1] + 1;
            }
        }
        return record;
    }
}

哈希表

1. 两数之和

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
        public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; i++) {
            if (hashtable.containsKey(target - nums[i])) {
                return new int[]{i, hashtable.get(target - nums[i])};
            } else {
                hashtable.put(nums[i], i);
            }
        }
        return new int[0];
    }
}

217. 存在重复元素

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public boolean containsDuplicate(int[] nums) {
      Set<Integer> set = new HashSet<Integer>();
      for(int x : nums){
          if(!set.add(x)){
              return true;
          }
      }
      return false;
    }
}

594. 最长和谐子序列

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int findLHS(int[] nums) {
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        int ans = 0;
        for (int i : nums) map.put(i, map.getOrDefault(i, 0) + 1);
        for (int i : nums)
            if (map.containsKey(i - 1)) ans = Math.max(ans, map.get(i) + map.get(i - 1));
        return ans;
    }
}

128. 最长连续序列

思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> num_set = new HashSet<Integer>();
        for (int num : nums) num_set.add(num);

        int longestStreak = 0;

        for (int num : num_set) {
            if (!num_set.contains(num - 1)) {
                int currentnum = num;
                int currentStreak = 1;
                while (num_set.contains(currentnum + 1)) {
                    currentnum += 1;
                    currentStreak += 1;
                }
                longestStreak = Math.max(longestStreak, currentStreak);
            }
        }

        return longestStreak;
    }
}

思路
时间复杂度:O(n)
空间复杂度:O(1)


  • 18
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值