跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

LeetCode Hot 100 算法题解(Java 版)

LeetCode Hot 100 高频算法题的 Java 解法,涵盖哈希、双指针、滑动窗口、动态规划、树、图论等核心知识点。包含题目思路分析与完整代码实现,旨在帮助开发者系统复习数据结构与算法,提升编码能力。

雪落无声发布于 2026/3/27更新于 2026/6/1238 浏览
LeetCode Hot 100 算法题解(Java 版)

LeetCode Hot 100 算法题解(Java 版)

哈希

两数之和

思路: 考虑到的点是一定有一个有效答案,并且是两数之和,返回的是 num 的序号,于是想到采取 hashmap 存放值和序号的映射。 从前向后遍历,先存在当前的 i,判断 target-num[i] 是否存在于数组即可。

解法

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

字母异位词分组

思路: 此题的难点,在于如何判断两个单词是否是同样数量和同样类型的字母组成的,但是题目限制了只有小写字母,于是我们可以考虑采取字符串重新排序,再组成一个新的字符串,如果存在 map 中说明就已经有了。

解法

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String, List<String>> res = new HashMap<>();
        String s;
        for (int i = 0; i < strs.length; i++) {
            [] str1 = strs[i].toCharArray();
            Arrays.sort(str1);
            s = String.valueOf(str1);
             (res.containsKey(s)) {
                List<String> tes = res.get(s);
                tes.add(strs[i]);
                res.put(s, tes);
            }  {
                List<String> tes =  <>();
                tes.add(strs[i]);
                res.put(s, tes);
            }
        }
          <>(res.values());
    }
}
char
if
else
new
ArrayList
return
new
ArrayList

最长连续序列

思路: 首先采取 set 去重,遍历 set,我们的思想是只遍历头部元素,其他元素不遍历。

解法

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            set.add(nums[i]);
        }
        int maxs = 0;
        for (int num : set) {
            if (!set.contains(num - 1)) {
                int now = num;
                int len = 1;
                while (set.contains(now + 1)) {
                    now++;
                    len++;
                }
                maxs = Math.max(len, maxs);
            }
        }
        return maxs;
    }
}

双指针

移动零

思路: 一个 left,一个 right,每次 right 为 0 时就和 left 交换,left 每次都会指向下一个 0。

解法

class Solution {
    public static void swap(int[] nums, int left, int right) {
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
    }

    public static void moveZeroes(int[] nums) {
        int n = nums.length, left = 0, right = 0;
        while (right < n) {
            if (nums[right] != 0) {
                swap(nums, left, right);
                left++;
            }
            right++;
        }
    }
}

盛最多水的容器

解法: 直接计算就好,每次移动较小的一边水槽就行。

class Solution {
    public int maxArea(int[] height) {
        int max = 0;
        int left = 0, right = height.length - 1, temp = 0;
        while (left < right) {
            temp = Math.min(height[left], height[right]) * (right - left);
            if (temp > max) {
                max = temp;
            }
            if (height[left] < height[right]) {
                left++;
            } else {
                right--;
            }
        }
        return max;
    }
}

三数之和

思路:

解法

class Solution {
    public static List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        int x, y, z, target;
        for (x = 0; x < nums.length; x++) {
            if (x > 0 && nums[x] == nums[x - 1]) {
                continue;
            }
            target = -nums[x];
            z = nums.length - 1;
            for (y = x + 1; y < nums.length; y++) {
                if (y > x + 1 && nums[y] == nums[y - 1]) {
                    continue;
                }
                while (y < z && nums[y] + nums[z] > target) {
                    z--;
                }
                if (y == z) {
                    break;
                }
                if (nums[y] + nums[z] == target) {
                    List<Integer> tmp = new ArrayList<>();
                    tmp.add(nums[x]);
                    tmp.add(nums[y]);
                    tmp.add(nums[z]);
                    res.add(tmp);
                }
            }
        }
        return res;
    }
}

接雨水

解法

class Solution {
    public static int trap(int[] height) {
        int n = height.length;
        if (n == 0) {
            return 0;
        }
        int[] left = new int[n];
        left[0] = height[0];
        for (int i = 1; i < n; ++i) {
            left[i] = Math.max(left[i - 1], height[i]);
        }
        int[] right = new int[n];
        right[n - 1] = height[n - 1];
        for (int i = n - 2; i >= 0; --i) {
            right[i] = Math.max(right[i + 1], height[i]);
        }
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            ans += Math.min(left[i], right[i]) - height[i];
        }
        return ans;
    }
}

滑动窗口

无重复字符的最长子串

思路: 采取滑动窗口的方法,用 HashMap 记录字符和字符的索引。 如果字符不存在于 HashMap 中,就加入 HashMap 中。 如果字符存在于 HashMap 中,就更新 beg 为重复字符的索引 +1,并删除 HashMap 中重复字符之前的所有字符。

解法

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s.length() == 0) {
            return 0;
        }
        int max = 1;
        char[] charArray = s.toCharArray();
        Map<Character, Integer> map = new HashMap<>();
        int beg = 0;
        for (int i = 0; i < charArray.length; i++) {
            if (!map.containsKey(charArray[i])) {
                map.put(charArray[i], i);
            } else {
                if (max < i - beg) {
                    max = i - beg;
                }
                for (int j = beg; j < map.get(charArray[i]); j++) {
                    map.remove(charArray[j]);
                }
                beg = map.get(charArray[i]) + 1;
                map.put(charArray[i], i);
            }
        }
        if (max < map.size()) {
            max = map.size();
        }
        return max;
    }
}

找到字符串中所有字母异位词

思路: 采取 hash 的思想,对比数组是否相等判断是否为子串。

解法

class Solution {
    public static List<Integer> findAnagrams(String s, String p) {
        List<Integer> res = new ArrayList<>();
        if (p.length() > s.length()) {
            return res;
        }
        int[] pl = new int[26];
        int[] sl = new int[26];
        for (int i = 0; i < p.length(); i++) {
            pl[p.charAt(i) - 'a']++;
            sl[s.charAt(i) - 'a']++;
        }
        if (Arrays.equals(pl, sl)) {
            res.add(0);
        }
        for (int i = 0; i < s.length() - p.length(); i++) {
            sl[s.charAt(i) - 'a']--;
            sl[s.charAt(i + p.length()) - 'a']++;
            if (Arrays.equals(pl, sl)) {
                res.add(i + 1);
            }
        }
        return res;
    }
}

子串

和为 k 的子数组

思路: 对于每个前缀和 s[i],只要统计前面有多少个前缀和 s[j] 等于 s[i]-k,就有多少个以 i 结尾、和为 k 的子数组。

解法

class Solution {
    public int subarraySum(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, 1);
        int res = 0;
        int total = 0;
        for (int i = 0; i < nums.length; i++) {
            total += nums[i];
            if (map.containsKey(total - k)) {
                res += map.get(total - k);
            }
            map.put(total, map.getOrDefault(total, 0) + 1);
        }
        return res;
    }
}

滑动窗口最大值

思路: 单调队列,具体思路见,主要就是考虑新进来的元素是窗口中最大,以及最大的元素出窗口。

解法

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int n = nums.length;
        Deque<Integer> win = new ArrayDeque<>();
        int[] res = new int[n - k + 1];
        for (int i = 0; i < n; i++) {
            while (!win.isEmpty() && nums[win.getLast()] <= nums[i]) {
                win.removeLast();
            }
            win.addLast(i);
            int beg = i - k + 1;
            while (win.getFirst() < beg) {
                win.removeFirst();
            }
            if (beg >= 0) {
                res[beg] = nums[win.getFirst()];
            }
        }
        return res;
    }
}

最小覆盖子串

思路: 对于此题我们要考虑的点是:1. 如何找到最小的;2. 如何快速判断 left 到 right 中是否包含子串。 这里采取了 tmap 存放了子串的每个字符出现的次数,tmap 的长度就是子串的不同字符个数 total。 smap 用来快速判断 left 和 right 之间是否存在子串,移动 right,如果出现了 t 中的字符并且数量和 t 中对应字符相同,now 加 1。 当 now 和 total 相同时,说明 left 和 right 之间存在子串。 就移动 left 缩短长度,如果减少了 t 中的字符,导致 now 不等于 total 就跳出缩短过程,继续扩大 right。

解法

class Solution {
    public static String minWindow(String s, String t) {
        if (s == null || t == null || s.length() == 0 || t.length() == 0 || s.length() < t.length()) {
            return "";
        }
        Map<Character, Integer> tmap = new HashMap<>();
        Map<Character, Integer> smap = new HashMap<>();
        for (int i = 0; i < t.length(); i++) {
            tmap.put(t.charAt(i), tmap.getOrDefault(t.charAt(i), 0) + 1);
        }
        int total = tmap.size();
        int now = 0;
        int left = 0, right = 0;
        int[] ans = new int[]{-1, 0, 0};
        while (left <= right && right < s.length()) {
            smap.put(s.charAt(right), smap.getOrDefault(s.charAt(right), 0) + 1);
            if (tmap.containsKey(s.charAt(right)) && tmap.get(s.charAt(right)).equals(smap.get(s.charAt(right)))) {
                now++;
            }
            if (now == total) {
                while (left <= right && now == total) {
                    char c = s.charAt(left);
                    if (tmap.containsKey(c)) {
                        if (ans[0] == -1 || ans[0] > right - left + 1) {
                            ans[0] = right - left + 1;
                            ans[1] = left;
                            ans[2] = right;
                        }
                    }
                    smap.put(s.charAt(left), smap.get(s.charAt(left)) - 1);
                    if (tmap.containsKey(s.charAt(left)) && smap.get(s.charAt(left)) < tmap.get(s.charAt(left))) {
                        now--;
                    }
                    left++;
                }
            }
            right++;
        }
        return ans[0] == -1 ? "" : s.substring(ans[1], ans[2] + 1);
    }
}

普通数组

最大子数组和

解法

class Solution {
    public static int maxSubArray(int[] nums) {
        int be = nums[0];
        int max = nums[0];
        for (int i = 1; i < nums.length; i++) {
            int x = be + nums[i];
            if (x > nums[i]) {
                be = x;
            } else {
                be = nums[i];
            }
            max = Math.max(max, be);
        }
        return max;
    }
}

合并区间

解法:

class Solution {
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
        List<int[]> mergedIntervals = new ArrayList<>();
        int beg = intervals[0][0];
        int end = intervals[0][1];
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] <= end) {
                end = Math.max(end, intervals[i][1]);
            } else {
                mergedIntervals.add(new int[]{beg, end});
                beg = intervals[i][0];
                end = intervals[i][1];
            }
        }
        mergedIntervals.add(new int[]{beg, end});
        return mergedIntervals.toArray(new int[mergedIntervals.size()][]);
    }
}

轮转数组

后 k 个倒序,0-len-k-1 倒序,整体倒序。

class Solution {
    public void reverse(int[] nums, int beg, int end) {
        int x;
        for (int i = beg; i <= (end + beg) / 2; i++) {
            x = nums[i];
            nums[i] = nums[beg + end - i];
            nums[beg + end - i] = x;
        }
    }

    public void rotate(int[] nums, int k) {
        k = k % nums.length;
        reverse(nums, 0, nums.length - 1 - k);
        reverse(nums, nums.length - k, nums.length - 1);
        reverse(nums, 0, nums.length - 1);
    }
}

除了自身以外数组的乘积

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n, i, j, r;
        r = 1;
        n = nums.length;
        int[] answer = new int[n];
        answer[0] = 1;
        for (i = 1; i < n; i++) {
            answer[i] = answer[i - 1] * nums[i - 1];
        }
        for (j = n - 1; j >= 0; j--) {
            answer[j] = answer[j] * r;
            r = r * nums[j];
        }
        return answer;
    }
}

缺失的第一个正数

思路: 使用占位的思想,对于一个位置 nums[i],他按照值来说,正常位次应该在 nums[nums[i]-1] 的位置,我们将所有的值放在该在的位置,然后遍历数组,哪个位置的值不满足要求,就返回这个位置的值就行。如果都满足要求,就返回数组长度 +1 就行。

解法

class Solution {
    public int firstMissingPositive(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            while (nums[i] >= 1 && nums[i] <= nums.length && nums[i] != nums[nums[i] - 1]) {
                int a = nums[nums[i] - 1];
                nums[nums[i] - 1] = nums[i];
                nums[i] = a;
            }
        }
        for (int i = 0; i < nums.length; ++i) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }
        return nums.length + 1;
    }
}

矩阵

矩阵置零

解法

class Solution {
    public void setZeroes(int[][] matrix) {
        int row = 1;
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                if (matrix[i][j] == 0) {
                    if (i == 0) {
                        row = 0;
                    } else {
                        matrix[i][0] = 0;
                    }
                    matrix[0][j] = 0;
                }
            }
        }
        for (int i = 1; i < matrix.length; i++) {
            if (matrix[i][0] == 0) {
                for (int j = 1; j < matrix[i].length; j++) {
                    matrix[i][j] = 0;
                }
            }
        }
        for (int i = 0; i < matrix[0].length; i++) {
            if (matrix[0][i] == 0) {
                for (int j = 1; j < matrix.length; j++) {
                    matrix[j][i] = 0;
                }
            }
        }
        if (row == 0) {
            for (int i = 0; i < matrix[0].length; i++) {
                matrix[0][i] = 0;
            }
        }
    }
}

螺旋数组

解法

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        int m, n;
        List<Integer> res = new ArrayList<>();
        m = matrix.length;
        n = matrix[0].length;
        int i = 0, j = 0;
        int x = 0;
        int minx = 0, miny = 0;
        while (n != 0 && m != 0) {
            if (x == 0) {
                while (j <= n - 1) {
                    res.add(matrix[i][j]);
                    j++;
                }
                j = n - 1;
                i++;
                if (i >= m) {
                    break;
                }
                x = 1;
            } else if (x == 1) {
                while (i <= m - 1) {
                    res.add(matrix[i][j]);
                    i++;
                }
                i = m - 1;
                j--;
                if (j < minx) {
                    break;
                }
                x = 2;
            } else if (x == 2) {
                while (j >= minx) {
                    res.add(matrix[i][j]);
                    j--;
                }
                j = minx;
                i--;
                x = 3;
            } else {
                while (i > miny) {
                    res.add(matrix[i][j]);
                    i--;
                }
                j++;
                x = 0;
                minx++;
                miny++;
                i = miny;
                m--;
                n--;
                if (i >= m || j >= n) {
                    break;
                }
            }
        }
        return res;
    }
}

旋转图像

解法

class Solution {
    public void rotate(int[][] matrix) {
        int x = 0;
        int n = matrix.length;
        for (int i = 0; i < n; i++) {
            for (int j = i; j < n; j++) {
                x = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = x;
            }
        }
        for (int i = 0; i < n / 2; i++) {
            for (int j = 0; j < n; j++) {
                x = matrix[j][i];
                matrix[j][i] = matrix[j][n - 1 - i];
                matrix[j][n - 1 - i] = x;
            }
        }
    }
}

搜索二维矩阵 II

思路: 根据样例而言,我们将行和列连起来看,即第一行 + 最后一列,按照右上角的元素来看,比这个元素大的就在列上,小的就在行上,基于这个发现,引申出来的做法:初始化为整个二维数组最右上角的元素。如果 target 等于这个元素,直接返回 true。如果说 target 小于这个元素,说明不可能存在于这一列上,那么就把这一列向前移动。如果说 target 大于这个元素,说明不可能存在于这一行上,那么就把这一行向下移动。

解法

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int x = 0;
        int y = matrix[x].length - 1;
        while (x < matrix.length && y >= 0) {
            if (matrix[x][y] == target) {
                return true;
            } else if (matrix[x][y] < target) {
                x++;
            } else {
                y--;
            }
        }
        return false;
    }
}

链表

相交链表

解法

class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lena = 0, lenb = 0;
        ListNode head1 = headA;
        while (head1 != null) {
            head1 = head1.next;
            lena++;
        }
        ListNode head2 = headB;
        while (head2 != null) {
            head2 = head2.next;
            lenb++;
        }
        head1 = headA;
        head2 = headB;
        while (lena > lenb) {
            head1 = head1.next;
            lena--;
        }
        while (lena < lenb) {
            head2 = head2.next;
            lenb--;
        }
        while (head2 != head1 && head1 != null && head2 != null) {
            head1 = head1.next;
            head2 = head2.next;
        }
        if (head1 != null && head2 != null) {
            return head1;
        }
        return null;
    }
}

反转链表

解法

class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode before = null;
        ListNode now = head;
        while (now != null) {
            ListNode a = now.next;
            now.next = before;
            before = now;
            now = a;
        }
        return before;
    }
}

回文链表

解法

class Solution {
    public boolean isPalindrome(ListNode head) {
        boolean res = true;
        if (head == null) {
            return false;
        }
        if (head.next == null) {
            return true;
        }
        ListNode beg = head;
        ListNode end = head;
        while (end != null) {
            beg = beg.next;
            end = end.next;
            if (end != null) {
                end = end.next;
            }
        }
        ListNode before = null;
        ListNode now = beg;
        while (now != null) {
            ListNode a = now.next;
            now.next = before;
            before = now;
            now = a;
        }
        ListNode hou = before;
        ListNode qian = head;
        while (qian != null && hou != null) {
            if (qian.val != hou.val) {
                res = false;
                break;
            }
            qian = qian.next;
            hou = hou.next;
        }
        return res;
    }
}

环形链表

思路:快慢指针。如果当块指针遇到慢指针就有环,遇不到能走到末尾就没环。

解法

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

环形链表 II

思路:pos 不是参数,只是评测内部的判断是否有环的参数。所以此题的目的是找到环的开始位置。 我们使用快慢指针,慢指针一次走 1,快指针一次走 2。如上图所示,在紫色点相遇。此时快指针走过的距离为:fast=a+b+n*(b+c)。由此可知慢指针走的距离是 fast/2 = a+b。由此整理可知道 2a+2b=a+b+nb+nc,a=c+(n-1)(b+c)。由此我们找相遇点,此时慢指针在紫色点,距离相遇点距离为 c,我们让一个节点从头结点向前走(每次 1 个),他们会在相遇点相遇。

解法

class Solution {
    public ListNode detectCycle(ListNode head) {
        if (head == null) {
            return null;
        }
        ListNode slow = head;
        ListNode fast = head;
        while (slow != null && fast != null) {
            slow = slow.next;
            fast = fast.next;
            if (fast == null) {
                return null;
            } else {
                fast = fast.next;
            }
            if (fast != null && slow != null) {
                if (fast == slow) {
                    break;
                }
            } else {
                return null;
            }
        }
        ListNode beg = head;
        while (beg != slow) {
            beg = beg.next;
            slow = slow.next;
        }
        return beg;
    }
}

合并两个有序链表

解法

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode res = new ListNode();
        ListNode x = res;
        while (list1 != null && list2 != null) {
            if (list1.val <= list2.val) {
                x.next = list1;
                list1 = list1.next;
            } else {
                x.next = list2;
                list2 = list2.next;
            }
            x = x.next;
        }
        if (list1 == null && list2 != null) {
            x.next = list2;
        }
        if (list2 == null && list1 != null) {
            x.next = list1;
        }
        return res.next;
    }
}

两数相加

解法

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode res = new ListNode();
        ListNode head = res;
        int num = 0;
        while (l1 != null && l2 != null) {
            int x = l1.val + l2.val + num;
            if (x >= 10) {
                num = 1;
                res.next = new ListNode(x % 10);
                res = res.next;
            } else {
                num = 0;
                res.next = new ListNode(x);
                res = res.next;
            }
            l1 = l1.next;
            l2 = l2.next;
        }
        if (l1 == null) {
            while (l2 != null) {
                int x = num + l2.val;
                if (x >= 10) {
                    num = 1;
                    res.next = new ListNode(x % 10);
                    res = res.next;
                } else {
                    num = 0;
                    res.next = new ListNode(x);
                    res = res.next;
                }
                l2 = l2.next;
            }
        } else {
            while (l1 != null) {
                int x = num + l1.val;
                if (x >= 10) {
                    num = 1;
                    res.next = new ListNode(x % 10);
                    res = res.next;
                } else {
                    num = 0;
                    res.next = new ListNode(x);
                    res = res.next;
                }
                l1 = l1.next;
            }
        }
        if (num == 1) {
            res.next = new ListNode(1);
            res = res.next;
        }
        return head.next;
    }
}

删除链表的倒数第 N 个节点

解法

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode fake = new ListNode();
        fake.next = head;
        ListNode fakehead = fake;
        ListNode x = head;
        ListNode y = head;
        int i = 1;
        while (i != n) {
            y = y.next;
            i++;
        }
        while (y.next != null) {
            x = x.next;
            y = y.next;
            fakehead = fakehead.next;
        }
        fakehead.next = x.next;
        return fake.next;
    }
}

两两交换链表中的节点

思路:采取一个空节点作为头结点(方便操作)。before 保存两两交换的前一个节点,a 为两两交换的第一个节点,be 为两两交换的第二个节点,next 保存下一组的第一个节点。

解法

class Solution {
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode first = new ListNode();
        first.next = head;
        ListNode be = first;
        ListNode mid = head;
        ListNode end = head.next;
        ListNode cun = new ListNode();
        while (true) {
            be.next = end;
            cun = end.next;
            end.next = mid;
            mid.next = cun;
            be = mid;
            mid = cun;
            if (mid == null) {
                break;
            }
            end = cun.next;
            if (end == null) {
                break;
            }
        }
        return first.next;
    }
}

K 个一组翻转链表

思路:类似于上题的思路。

解法

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if (k == 1) {
            return head;
        }
        ListNode fakehead = new ListNode();
        fakehead.next = head;
        ListNode pre = fakehead;
        ListNode beg = head;
        ListNode end = head;
        while (beg != null && end != null) {
            for (int i = 0; i < k - 1; i++) {
                end = end.next;
                if (end == null) {
                    return fakehead.next;
                }
            }
            ListNode m = new ListNode();
            ListNode beg1 = beg;
            ListNode nextbeg = end.next;
            while (beg1 != end) {
                m = beg1.next;
                beg1.next = end.next;
                end.next = beg1;
                beg1 = m;
            }
            pre.next = end;
            pre = beg;
            beg = beg.next;
            end = beg;
        }
        return fakehead.next;
    }
}

随机链表的复制

解法

class Solution {
    public Node copyRandomList(Node head) {
        Map<Node, Integer> map = new HashMap<>();
        List<Node> list = new ArrayList<>();
        int i = 0;
        Node beg = head;
        while (beg != null) {
            map.put(beg, i);
            i++;
            beg = beg.next;
        }
        Node res = new Node(0);
        Node x = res;
        beg = head;
        while (beg != null) {
            Node tes = new Node(beg.val);
            x.next = tes;
            x = x.next;
            beg = beg.next;
            list.add(tes);
        }
        beg = head;
        x = res.next;
        int num;
        while (beg != null) {
            if (beg.random != null) {
                num = map.get(beg.random);
                x.random = list.get(num);
            } else {
                x.random = null;
            }
            beg = beg.next;
            x = x.next;
        }
        return res.next;
    }
}

排序链表

解法

class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode mid = getMiddle(head);
        ListNode rightHead = mid.next;
        mid.next = null;
        ListNode left = sortList(head);
        ListNode right = sortList(rightHead);
        return merge(left, right);
    }

    private ListNode getMiddle(ListNode head) {
        if (head == null) return null;
        ListNode slow = head;
        ListNode fast = head.next;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }

    private ListNode merge(ListNode l1, ListNode l2) {
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                tail.next = l1;
                l1 = l1.next;
            } else {
                tail.next = l2;
                l2 = l2.next;
            }
            tail = tail.next;
        }
        if (l1 != null) tail.next = l1;
        if (l2 != null) tail.next = l2;
        return dummy.next;
    }
}

合并 K 个升序链表

思路:lists 一分为二(尽量均分),先合并前一半的链表,再合并后一半的链表,然后把这两个链表合并成最终的链表。

解法

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        return merge(lists, 0, lists.length - 1);
    }

    public ListNode merge(ListNode[] lists, int l, int r) {
        if (l == r) {
            return lists[l];
        }
        if (l > r) {
            return null;
        }
        int mid = (l + r) / 2;
        return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
    }

    public ListNode mergeTwoLists(ListNode a, ListNode b) {
        if (a == null || b == null) {
            return a != null ? a : b;
        }
        ListNode head = new ListNode(0);
        ListNode tail = head, aPtr = a, bPtr = b;
        while (aPtr != null && bPtr != null) {
            if (aPtr.val < bPtr.val) {
                tail.next = aPtr;
                aPtr = aPtr.next;
            } else {
                tail.next = bPtr;
                bPtr = bPtr.next;
            }
            tail = tail.next;
        }
        tail.next = (aPtr != null ? aPtr : bPtr);
        return head.next;
    }
}

LRU 缓存

思路:直接使用 LinkedHashMap,它本身就实现了 LRU。get 之前先把 map 中的 key 删了再插入。put 之前先判断是否存在,存在就删除再插入,返回就行,如果不存在就判断 size,如果 size 不满,插入返回就好。如果 size 满了,就用迭代器取出 key 的第一个(最久未使用的),删除。

解法

class LRUCache {
    private static class Node {
        int key, value;
        Node prev, next;
        Node(int k, int v) { key = k; value = v; }
    }

    private final int capacity;
    private final Node dummy = new Node(0, 0);
    private final Map<Integer, Node> keyToNode = new HashMap<>();

    public LRUCache(int capacity) {
        this.capacity = capacity;
        dummy.prev = dummy;
        dummy.next = dummy;
    }

    private Node getNode(int key) {
        if (!keyToNode.containsKey(key)) {
            return null;
        }
        Node node = keyToNode.get(key);
        remove(node);
        pushFront(node);
        return node;
    }

    private void remove(Node x) {
        x.prev.next = x.next;
        x.next.prev = x.prev;
    }

    private void pushFront(Node x) {
        x.prev = dummy;
        x.next = dummy.next;
        x.prev.next = x;
        x.next.prev = x;
    }

    public int get(int key) {
        if (!keyToNode.containsKey(key)) {
            return -1;
        }
        Node x = getNode(key);
        return x.value;
    }

    public void put(int key, int value) {
        Node node = getNode(key);
        if (node != null) {
            node.value = value;
            return;
        }
        node = new Node(key, value);
        keyToNode.put(key, node);
        pushFront(node);
        if (keyToNode.size() > capacity) {
            Node backNode = dummy.prev;
            keyToNode.remove(backNode.key);
            remove(backNode);
        }
    }
}

二叉树

二叉树的中序遍历

解法

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        find(root, res);
        return res;
    }

    public void find(TreeNode root, List<Integer> res) {
        if (root == null) {
            return;
        }
        find(root.left, res);
        res.add(root.val);
        find(root.right, res);
    }
}

二叉树的最大深度

解法

class Solution {
    public int max = 0;

    public int maxDepth(TreeNode root) {
        findmax(root, 1);
        return max;
    }

    public void findmax(TreeNode root, int len) {
        if (root == null) {
            return;
        }
        if (len > max) {
            max = len;
        }
        findmax(root.left, len + 1);
        findmax(root.right, len + 1);
    }
}

翻转二叉树

解法

class Solution {
    public TreeNode invertTree(TreeNode root) {
        reverse(root);
        return root;
    }

    public void reverse(TreeNode root) {
        if (root == null) {
            return;
        }
        if (root.left != null || root.right != null) {
            TreeNode s = root.left;
            root.left = root.right;
            root.right = s;
        }
        reverse(root.left);
        reverse(root.right);
    }
}

对称二叉树

解法

class Solution {
    boolean res = true;

    public void check(TreeNode r1, TreeNode r2) {
        if (res == false || (r1 == null && r2 == null)) {
            return;
        }
        if ((r1 == null && r2 != null) || (r1 != null && r2 == null)) {
            res = false;
            return;
        }
        if (r1.val != r2.val) {
            res = false;
            return;
        }
        check(r1.left, r2.right);
        check(r1.right, r2.left);
    }

    public boolean isSymmetric(TreeNode root) {
        TreeNode left = root.left;
        TreeNode right = root.right;
        check(left, right);
        return res;
    }
}

二叉树的直径

解法

class Solution {
    int ans;

    public int diameterOfBinaryTree(TreeNode root) {
        ans = 1;
        depth(root);
        return ans - 1;
    }

    public int depth(TreeNode node) {
        if (node == null) {
            return 0;
        }
        int L = depth(node.left);
        int R = depth(node.right);
        ans = Math.max(ans, L + R + 1);
        return Math.max(L, R) + 1;
    }
}

二叉树的层序遍历

解法

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        levelOrderleft(root, 0, res);
        return res;
    }

    public void levelOrderleft(TreeNode root, int height, List<List<Integer>> res) {
        if (root == null) {
            return;
        }
        if (res.size() - 1 < height) {
            List<Integer> tes = new ArrayList<>();
            res.add(tes);
        }
        res.get(height).add(root.val);
        if (root.left != null) {
            levelOrderleft(root.left, height + 1, res);
        }
        if (root.right != null) {
            levelOrderleft(root.right, height + 1, res);
        }
    }
}

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

解法

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

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

验证二叉搜索树

解法

class Solution {
    public boolean isValidBST(TreeNode root) {
        Deque<TreeNode> stack = new LinkedList<>();
        double inorder = -Double.MAX_VALUE;
        while (!stack.isEmpty() || root != null) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            if (root.val <= inorder) {
                return false;
            }
            inorder = root.val;
            root = root.right;
        }
        return true;
    }
}

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

解法

class Solution {
    int x = 1;
    int num;

    public void mid(TreeNode root, int k) {
        if (root == null || x > k) {
            return;
        }
        mid(root.left, k);
        if (x == k) {
            num = root.val;
        }
        x++;
        mid(root.right, k);
    }

    public int kthSmallest(TreeNode root, int k) {
        mid(root, k);
        return num;
    }
}

二叉树的右视图

解法

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        find(root, res, 1);
        return res;
    }

    public void find(TreeNode root, List<Integer> res, int heigh) {
        if (root == null) {
            return;
        }
        if (res.size() < heigh) {
            res.add(root.val);
        }
        find(root.right, res, heigh + 1);
        find(root.left, res, heigh + 1);
    }
}

二叉树展开为链表

思路:

  1. 如果当前节点为空,返回。
  2. 递归右子树。
  3. 递归左子树。
  4. 把 root.left 置为空。
  5. 头插法,把 root 插在 head 的前面,也就是 root.right=head。
  6. 现在 root 是链表的头节点,把 head 更新为 root。

解法

class Solution {
    private TreeNode head;

    public void flatten(TreeNode root) {
        if (root == null) {
            return;
        }
        flatten(root.right);
        flatten(root.left);
        root.left = null;
        root.right = head;
        head = root;
    }
}

从前序与中序遍历序列构造二叉树

解法

class Solution {
    public Map<Integer, Integer> indexMap;

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        int n = inorder.length;
        indexMap = new HashMap<>();
        for (int i = 0; i < n; i++) {
            indexMap.put(inorder[i], i);
        }
        return findroot(preorder, inorder, 0, n - 1, 0, n - 1);
    }

    public TreeNode findroot(int[] preorder, int[] inorder, int preleft, int preright, int inleft, int inright) {
        if (preleft > preright) {
            return null;
        }
        int root_num = preleft;
        int in = indexMap.get(preorder[root_num]);
        TreeNode root = new TreeNode(preorder[root_num]);
        root.left = findroot(preorder, inorder, preleft + 1, preleft + in - inleft, inleft, in - 1);
        root.right = findroot(preorder, inorder, preleft + in - inleft + 1, preright, in + 1, inright);
        return root;
    }
}

路径总和 III

思路:前缀和。使用 map,key 为到当前节点前的前缀和,value 为个数。dfs()包含的参数,只介绍下 sum,为到这个节点前的所有前缀和,其他的都知道。到一个节点,先前缀和 + 这个节点值 sum。判断这个 sum-目标值后是否在 map 中存在并且大于 0,满足就将 res+(map 中的值)。然后将这个 sum 放入 map 中。遍历左右。出来后将这个 map(sum)减 1。

解法

class Solution {
    public int res = 0;

    public int pathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return 0;
        }
        Map<Long, Integer> map = new HashMap<>();
        map.put(0L, 1);
        dfs(root, targetSum, map, 0L);
        return res;
    }

    public void dfs(TreeNode root, int targetSum, Map<Long, Integer> map, Long sum) {
        if (root == null) {
            return;
        }
        sum += root.val;
        if (map.containsKey(sum - targetSum) && map.get(sum - targetSum) > 0) {
            res += map.get(sum - targetSum);
        }
        map.put(sum, map.getOrDefault(sum, 0) + 1);
        dfs(root.left, targetSum, map, sum);
        dfs(root.right, targetSum, map, sum);
        map.put(sum, map.get(sum) - 1);
    }
}

二叉树的最近公共祖先

解法

class Solution {
    public List<TreeNode> list1 = new ArrayList<>();
    public List<TreeNode> list2 = new ArrayList<>();

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        List<TreeNode> res = new ArrayList<>();
        dfs(root, p, q, res);
        TreeNode result = root;
        for (int i = list1.size() - 1; i >= 0; i--) {
            TreeNode s = list1.get(i);
            if (list2.contains(s)) {
                return s;
            }
        }
        return result;
    }

    public void dfs(TreeNode root, TreeNode p, TreeNode q, List<TreeNode> res) {
        if (root == null || (list1.size() != 0 && list2.size() != 0)) {
            return;
        }
        res.add(root);
        if (root == p) {
            list1 = new ArrayList<>(res);
        }
        if (root == q) {
            list2 = new ArrayList<>(res);
        }
        dfs(root.left, p, q, res);
        dfs(root.right, p, q, res);
        res.remove(res.size() - 1);
    }
}

二叉树的最大路径和

解法

class Solution {
    public int max = Integer.MIN_VALUE;

    public int maxPathSum(TreeNode root) {
        findmax(root);
        return max;
    }

    public int findmax(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = Math.max(findmax(root.left), 0);
        int right = Math.max(findmax(root.right), 0);
        int sum = root.val + left + right;
        max = Math.max(sum, max);
        return root.val + Math.max(left, right);
    }
}

图论

岛屿数量

简单的深搜。

解法

class Solution {
    public int sum = 0;

    public int numIslands(char[][] grid) {
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (grid[i][j] == '1') {
                    find(grid, i, j);
                    sum++;
                }
            }
        }
        return sum;
    }

    public void find(char[][] grid, int i, int j) {
        if (i < 0 || i > grid.length - 1 || j < 0 || j > grid[0].length - 1 || grid[i][j] != '1') {
            return;
        }
        grid[i][j] = '0';
        find(grid, i - 1, j);
        find(grid, i + 1, j);
        find(grid, i, j - 1);
        find(grid, i, j + 1);
    }
}

腐烂的橘子

思路:1 遍历网格中所有腐烂橘子(值≥2)的位置,对每个腐烂橘子的上下左右四个方向格子执行 DFS,DFS 中先判断边界、空格子(值为 0)、非新鲜且代际≤当前传入代际的情况,满足则直接返回,否则将当前格子标记为当前代际值(代表该时间点腐烂),并递归处理该格子的四个方向(代际 + 1);2 二次遍历网格,先检查是否存在未腐烂的新鲜橘子(值为 1),若有则返回 -1,同时计算每个腐烂橘子代际值与初始腐烂值(2)的差值,更新最大差值到 max 变量;3 最终返回 max,该值即为所有新鲜橘子被腐烂的最大时间(无新鲜橘子时返回 0)。

解法

class Solution {
    public int max = 0;

    public int orangesRotting(int[][] grid) {
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[i].length; j++) {
                if (grid[i][j] >= 2) {
                    dfs(grid, i - 1, j, grid[i][j] + 1);
                    dfs(grid, i + 1, j, grid[i][j] + 1);
                    dfs(grid, i, j - 1, grid[i][j] + 1);
                    dfs(grid, i, j + 1, grid[i][j] + 1);
                }
            }
        }
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[i].length; j++) {
                if (grid[i][j] == 1) {
                    return -1;
                }
                max = Math.max(max, grid[i][j] - 2);
            }
        }
        return max;
    }

    public void dfs(int[][] grid, int i, int j, int gen) {
        if (i < 0 || i > grid.length - 1 || j < 0 || j > grid[0].length - 1 || grid[i][j] == 0 || (grid[i][j] != 1 && grid[i][j] <= gen)) {
            return;
        }
        grid[i][j] = gen;
        dfs(grid, i - 1, j, gen + 1);
        dfs(grid, i + 1, j, gen + 1);
        dfs(grid, i, j - 1, gen + 1);
        dfs(grid, i, j + 1, gen + 1);
    }
}

课程表

宽搜思想:将出度信息保存在一个 grid。使用一个队列。每次放入新的起点。

解法

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        int[] tes = new int[numCourses];
        List<List<Integer>> grid = new ArrayList<>();
        for (int i = 0; i < numCourses; i++) {
            grid.add(new ArrayList<Integer>());
        }
        for (int i = 0; i < prerequisites.length; i++) {
            grid.get(prerequisites[i][1]).add(prerequisites[i][0]);
            tes[prerequisites[i][0]]++;
        }
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numCourses; i++) {
            if (tes[i] == 0) {
                queue.offer(i);
            }
        }
        int len = 0;
        while (!queue.isEmpty()) {
            len++;
            int beg = queue.poll();
            for (int i = 0; i < grid.get(beg).size(); i++) {
                tes[grid.get(beg).get(i)]--;
                if (tes[grid.get(beg).get(i)] == 0) {
                    queue.offer(grid.get(beg).get(i));
                }
            }
        }
        return len == numCourses;
    }
}

实现前缀树

class Trie {
    public Trie[] child;
    public boolean isend;

    public Trie() {
        child = new Trie[26];
        isend = false;
    }

    public void insert(String word) {
        Trie node = this;
        for (int i = 0; i < word.length(); i++) {
            char a = word.charAt(i);
            if (node.child[a - 'a'] == null) {
                node.child[a - 'a'] = new Trie();
            }
            node = node.child[a - 'a'];
        }
        node.isend = true;
    }

    public boolean search(String word) {
        Trie node = this;
        for (int i = 0; i < word.length(); i++) {
            char a = word.charAt(i);
            if (node.child[a - 'a'] == null) {
                return false;
            }
            node = node.child[a - 'a'];
        }
        if (node.isend == false) {
            return false;
        }
        return true;
    }

    public boolean startsWith(String prefix) {
        Trie node = this;
        for (int i = 0; i < prefix.length(); i++) {
            char a = prefix.charAt(i);
            if (node.child[a - 'a'] == null) {
                return false;
            }
            node = node.child[a - 'a'];
        }
        return true;
    }
}

回溯

全排列

解法

class Solution {
    public List<List<Integer>> res;
    public List<Integer> tes;

    public List<List<Integer>> permute(int[] nums) {
        res = new ArrayList<>();
        tes = new ArrayList<>();
        int[] zai = new int[nums.length];
        dfs(nums, zai);
        return res;
    }

    public void dfs(int[] nums, int[] zai) {
        if (tes.size() == zai.length) {
            res.add(new ArrayList<>(tes));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (zai[i] == 0) {
                zai[i] = 1;
                tes.add(nums[i]);
                dfs(nums, zai);
                zai[i] = 0;
                tes.remove(tes.size() - 1);
            }
        }
    }
}

子集

仿照上题的思路。

解法

class Solution {
    public List<List<Integer>> res;

    public List<List<Integer>> subsets(int[] nums) {
        int[] zai = new int[nums.length];
        List<Integer> tes = new ArrayList<>();
        res = new ArrayList<>();
        for (int i = 0; i <= nums.length; i++) {
            dfs(nums, tes, i, 0);
        }
        return res;
    }

    public void dfs(int[] nums, List<Integer> tes, int len, int beg) {
        if (tes.size() == len) {
            res.add(new ArrayList<>(tes));
            return;
        }
        for (int i = beg; i < nums.length; i++) {
            tes.add(nums[i]);
            dfs(nums, tes, len, i + 1);
            tes.remove(tes.size() - 1);
        }
    }
}

电话号码的字母组合

解法

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

    public void find(List<String> res, Map<Character, String> num, String digits, int beg, StringBuffer tes) {
        if (beg == digits.length()) {
            res.add(tes.toString());
            return;
        }
        String a = num.get(digits.charAt(beg));
        for (int j = 0; j < a.length(); j++) {
            tes.append(a.charAt(j));
            find(res, num, digits, beg + 1, tes);
            tes.deleteCharAt(beg);
        }
    }
}

组合总数

解法

class Solution {
    public List<List<Integer>> res;

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<Integer> tes = new ArrayList<>();
        res = new ArrayList<>();
        find(candidates, target, tes, 0, 0);
        return res;
    }

    public void find(int[] candidates, int target, List<Integer> tes, int sum, int beg) {
        if (sum == target) {
            res.add(new ArrayList<>(tes));
            return;
        }
        for (int i = beg; i < candidates.length; i++) {
            if (sum + candidates[i] <= target) {
                tes.add(candidates[i]);
                find(candidates, target, tes, sum + candidates[i], i);
                tes.remove(tes.size() - 1);
            }
        }
    }
}

括号生成

解法

class Solution {
    public List<String> res;

    public List<String> generateParenthesis(int n) {
        res = new ArrayList<>();
        StringBuffer s = new StringBuffer();
        int[] zai = new int[2];
        zai[0] = n;
        zai[1] = n;
        find(zai, s);
        return res;
    }

    public void find(int[] zai, StringBuffer s) {
        if (zai[0] == 0 && zai[1] == 0) {
            res.add(s.toString());
            return;
        }
        for (int i = 0; i <= 1; i++) {
            if (i == 0 && zai[0] > 0) {
                s.append('(');
                zai[0]--;
                find(zai, s);
                zai[0]++;
                s.deleteCharAt(s.length() - 1);
            }
            if (i == 1 && zai[1] > 0 && zai[0] < zai[1]) {
                s.append(')');
                zai[1]--;
                find(zai, s);
                zai[1]++;
                s.deleteCharAt(s.length() - 1);
            }
        }
    }
}

单词搜索

解法

class Solution {
    boolean isexist = false;

    public boolean exist(char[][] board, String word) {
        int[][] zai = new int[board.length][board[0].length];
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                if (board[i][j] == word.charAt(0)) {
                    zai[i][j] = 1;
                    find(board, i, j, word, 1, zai);
                    zai[i][j] = 0;
                }
                if (isexist) {
                    return isexist;
                }
            }
        }
        return isexist;
    }

    public void find(char[][] board, int i, int j, String word, int index, int[][] zai) {
        if (index == word.length() || isexist) {
            isexist = true;
            return;
        }
        if (i - 1 >= 0 && zai[i - 1][j] != 1 && board[i - 1][j] == word.charAt(index)) {
            zai[i - 1][j] = 1;
            find(board, i - 1, j, word, index + 1, zai);
            zai[i - 1][j] = 0;
        }
        if (i + 1 < board.length && zai[i + 1][j] != 1 && board[i + 1][j] == word.charAt(index)) {
            zai[i + 1][j] = 1;
            find(board, i + 1, j, word, index + 1, zai);
            zai[i + 1][j] = 0;
        }
        if (j - 1 >= 0 && zai[i][j - 1] != 1 && board[i][j - 1] == word.charAt(index)) {
            zai[i][j - 1] = 1;
            find(board, i, j - 1, word, index + 1, zai);
            zai[i][j - 1] = 0;
        }
        if (j + 1 < board[i].length && zai[i][j + 1] != 1 && board[i][j + 1] == word.charAt(index)) {
            zai[i][j + 1] = 1;
            find(board, i, j + 1, word, index + 1, zai);
            zai[i][j + 1] = 0;
        }
    }
}

分割回文串

解法

class Solution {
    public List<List<String>> partition(String s) {
        List<List<String>> res = new ArrayList<>();
        int[][] dp = new int[s.length()][s.length()];
        dfs(s, 0, res, dp, new ArrayList<>());
        return res;
    }

    public void dfs(String s, int index, List<List<String>> res, int[][] dp, List<String> tes) {
        if (index == s.length()) {
            res.add(new ArrayList<>(tes));
            return;
        }
        for (int i = index; i < s.length(); ++i) {
            if (ishui(index, i, s, dp)) {
                tes.add(s.substring(index, i + 1));
                dfs(s, i + 1, res, dp, tes);
                tes.remove(tes.size() - 1);
            }
        }
    }

    public boolean ishui(int left, int right, String s, int[][] dp) {
        if (dp[left][right] == 1) {
            return true;
        }
        if (dp[left][right] == -1) {
            return false;
        }
        while (left != right && left < right) {
            if (s.charAt(left) != s.charAt(right)) {
                dp[left][right] = -1;
                return false;
            }
            left++;
            right--;
        }
        dp[left][right] = 1;
        return true;
    }
}

N 皇后

解法

class Solution {
    public List<List<String>> solveNQueens(int n) {
        String[][] dp = new String[n][n];
        int[] col = new int[n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                dp[i][j] = ".";
            }
        }
        List<List<String>> res = new ArrayList<>();
        find(0, n, dp, res, col);
        return res;
    }

    public void find(int index, int n, String[][] dp, List<List<String>> res, int[] col) {
        if (index == n) {
            List<String> tes = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                String s = "";
                for (int j = 0; j < n; j++) {
                    s += dp[i][j];
                }
                tes.add(s);
            }
            res.add(tes);
            return;
        }
        for (int i = 0; i < n; i++) {
            if (isok(dp, index, i, n, col) || index == 0) {
                dp[index][i] = "Q";
                col[i] = 1;
                find(index + 1, n, dp, res, col);
                col[i] = 0;
                dp[index][i] = ".";
            }
        }
    }

    public boolean isok(String[][] dp, int x, int y, int n, int[] col) {
        if (col[y] == 1) {
            return false;
        }
        int i = x - 1;
        int j = y - 1;
        while (i >= 0 && j >= 0) {
            if (dp[i][j].equals("Q")) {
                return false;
            }
            i--;
            j--;
        }
        i = x - 1;
        j = y + 1;
        while (i >= 0 && j < n) {
            if (dp[i][j].equals("Q")) {
                return false;
            }
            i--;
            j++;
        }
        return true;
    }
}

二分查找

搜索插入位置

解法

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

搜索二维矩阵

解法

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int row = -1;
        for (int i = 0; i < matrix.length; i++) {
            if (target <= matrix[i][matrix[i].length - 1]) {
                row = i;
                break;
            }
        }
        if (row == -1 || target < matrix[row][0]) {
            return false;
        }
        int left = 0;
        int right = matrix[row].length - 1;
        int mid = 0;
        while (left <= right) {
            mid = (left + right) / 2;
            if (matrix[row][mid] == target) {
                return true;
            } else if (matrix[row][mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return false;
    }
}

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

解法

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] res = new int[]{-1, -1};
        if (nums == null || nums.length == 0) {
            return res;
        }
        int left = 0;
        int right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        if (left >= nums.length || nums[left] != target) {
            return res;
        }
        res[0] = left;
        left = 0;
        right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] <= target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        if (right < 0 || nums[right] != target) {
            return res;
        }
        res[1] = right;
        return res;
    }
}

搜索旋转排序数组

解法

class Solution {
    public int search(int[] nums, int target) {
        int beg = 0;
        int end = nums.length - 1;
        while (beg <= end) {
            int mid = beg + (end - beg) / 2;
            if (target == nums[mid]) {
                return mid;
            }
            if (nums[beg] <= nums[mid]) {
                if (target <= nums[mid] && target >= nums[beg]) {
                    end = mid - 1;
                } else {
                    beg = mid + 1;
                }
            } else {
                if (target > nums[mid] && target <= nums[end]) {
                    beg = mid + 1;
                } else {
                    end = mid - 1;
                }
            }
        }
        return -1;
    }
}

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

解法

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

寻找两个正序数组的中位数

解法

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int[] res = nums1;
        if (nums1.length > nums2.length) {
            int[] temp = nums1;
            nums1 = nums2;
            nums2 = temp;
        }
        int m = nums1.length;
        int n = nums2.length;
        int left = 0, right = m;
        while (left <= right) {
            int i = (left + right) / 2;
            int j = (m + n + 1) / 2 - i;
            int left1, right1, left2, right2;
            if (i == 0) {
                left1 = Integer.MIN_VALUE;
            } else {
                left1 = nums1[i - 1];
            }
            if (i == m) {
                right1 = Integer.MAX_VALUE;
            } else {
                right1 = nums1[i];
            }
            if (j == 0) {
                left2 = Integer.MIN_VALUE;
            } else {
                left2 = nums2[j - 1];
            }
            if (j == n) {
                right2 = Integer.MAX_VALUE;
            } else {
                right2 = nums2[j];
            }
            if (left1 <= right2 && left2 <= right1) {
                if ((m + n) % 2 == 0) {
                    return (Math.max(left1, left2) + Math.min(right1, right2)) / 2.0;
                } else {
                    return Math.max(left1, left2) + 0.0;
                }
            } else if (left1 > right2) {
                right = i - 1;
            } else {
                left = i + 1;
            }
        }
        return 0;
    }
}

栈

有效的括号

解法

class Solution {
    public boolean isValid(String s) {
        Stack<Character> left = new Stack<>();
        char c;
        for (int i = 0; i < s.length(); i++) {
            c = s.charAt(i);
            if (c == '(' || c == '{' || c == '[') {
                left.push(c);
            } else if (c == ')') {
                if (!left.isEmpty() && left.peek() == '(') {
                    left.pop();
                } else {
                    return false;
                }
            } else if (c == '}') {
                if (!left.isEmpty() && left.peek() == '{') {
                    left.pop();
                } else {
                    return false;
                }
            } else {
                if (!left.isEmpty() && left.peek() == '[') {
                    left.pop();
                } else {
                    return false;
                }
            }
        }
        if (left.isEmpty()) {
            return true;
        } else {
            return false;
        }
    }
}

最小栈

解法

class MinStack {
    Stack<Integer> stack;
    Stack<Integer> minStack;

    public MinStack() {
        stack = new Stack<Integer>();
        minStack = new Stack<Integer>();
        minStack.push(Integer.MAX_VALUE);
    }

    public void push(int val) {
        stack.push(val);
        if (val < minStack.peek()) {
            minStack.push(val);
        } else {
            minStack.push(minStack.peek());
        }
    }

    public void pop() {
        stack.pop();
        minStack.pop();
    }

    public int top() {
        return stack.peek();
    }

    public int getMin() {
        return minStack.peek();
    }
}

字符串解码

class Solution {
    public String decodeString(String s) {
        Stack<Integer> num = new Stack<>();
        Stack<String> value = new Stack<>();
        StringBuilder sb = new StringBuilder();
        int i = 0;
        while (i < s.length()) {
            char a = s.charAt(i);
            if (a == '[') {
                value.push(sb.toString());
                sb.setLength(0);
                i++;
            } else if (Character.isDigit(a)) {
                int x = a - '0';
                i++;
                while (i < s.length() && Character.isDigit(s.charAt(i))) {
                    x = x * 10 + (s.charAt(i) - '0');
                    i++;
                }
                num.push(x);
            } else if (a == ']') {
                int x = num.isEmpty() ? 1 : num.pop();
                String res = sb.toString();
                sb.setLength(0);
                for (int j = 0; j < x; j++) {
                    sb.append(res);
                }
                if (!value.isEmpty()) {
                    sb.insert(0, value.pop());
                }
                i++;
            } else {
                sb.append(a);
                i++;
            }
        }
        return sb.toString();
    }
}

每日温度

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        Deque<Integer> xu = new LinkedList<>();
        int n = temperatures.length;
        int[] res = new int[n];
        for (int i = 0; i < n; i++) {
            while (!xu.isEmpty() && temperatures[i] > temperatures[xu.peek()]) {
                int num = xu.pop();
                res[num] = i - num;
            }
            xu.push(i);
        }
        return res;
    }
}

柱状图中的最大的矩形

解法

class Solution {
    public int largestRectangleArea(int[] heights) {
        int[] left = new int[heights.length];
        int[] right = new int[heights.length];
        Deque<Integer> stack = new LinkedList<>();
        for (int i = 0; i < left.length; i++) {
            left[i] = -1;
            right[i] = heights.length;
        }
        for (int i = 0; i < heights.length; i++) {
            while (!stack.isEmpty() && heights[i] < heights[stack.peek()]) {
                right[stack.peek()] = i;
                stack.pop();
            }
            if (!stack.isEmpty()) {
                left[i] = stack.peek();
            }
            stack.push(i);
        }
        int max = 0;
        for (int i = 0; i < heights.length; i++) {
            max = Math.max(max, (right[i] - left[i] - 1) * heights[i]);
        }
        return max;
    }
}

堆

数组中的第 K 个最大元素

解法

class Solution {
    public int findKthLargest(int[] _nums, int k) {
        int n = _nums.length;
        return quickselect(_nums, 0, n - 1, n - k);
    }

    // 快排思想
    int quickselect(int[] nums, int l, int r, int k) {
        if (l == r) return nums[k];
        int x = nums[l], i = l - 1, j = r + 1;
        while (i < j) {
            do i++; while (nums[i] < x);
            do j--; while (nums[j] > x);
            if (i < j) {
                int tmp = nums[i];
                nums[i] = nums[j];
                nums[j] = tmp;
            }
        }
        if (k <= j) return quickselect(nums, l, j, k);
        else return quickselect(nums, j + 1, r, k);
    }
}

前 K 个高频元素

解法

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() {
            public int compare(int[] m, int[] n) {
                return m[1] - n[1];
            }
        });
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            int num = entry.getKey(), count = entry.getValue();
            if (queue.size() == k) {
                if (queue.peek()[1] < count) {
                    queue.poll();
                    queue.offer(new int[]{num, count});
                }
            } else {
                queue.offer(new int[]{num, count});
            }
        }
        int[] ret = new int[k];
        for (int i = 0; i < k; ++i) {
            ret[i] = queue.poll()[0];
        }
        return ret;
    }
}

数据流的中位数

解法

class MedianFinder {
    PriorityQueue<Integer> queMin;
    PriorityQueue<Integer> queMax;

    public MedianFinder() {
        queMin = new PriorityQueue<Integer>((a, b) -> (b - a));
        queMax = new PriorityQueue<Integer>((a, b) -> (a - b));
    }

    public void addNum(int num) {
        if (queMin.isEmpty() || num <= queMin.peek()) {
            queMin.offer(num);
            if (queMax.size() + 1 < queMin.size()) {
                queMax.offer(queMin.poll());
            }
        } else {
            queMax.offer(num);
            if (queMax.size() > queMin.size()) {
                queMin.offer(queMax.poll());
            }
        }
    }

    public double findMedian() {
        if (queMin.size() > queMax.size()) {
            return queMin.peek();
        }
        return (queMin.peek() + queMax.peek()) / 2.0;
    }
}

贪心算法

买卖股票的最佳时机

解法

class Solution {
    public int maxProfit(int[] prices) {
        int max = 0, min = prices[prices.length - 1];
        for (int i = prices.length - 2; i >= 0; i--) {
            if (prices[i] > min) {
                min = prices[i];
            } else {
                if (max < min - prices[i]) {
                    max = min - prices[i];
                }
            }
        }
        return max;
    }
}

跳跃游戏

解法

class Solution {
    public boolean canJump(int[] nums) {
        int end = nums.length - 1;
        for (int i = nums.length - 2; i >= 0; i--) {
            if (i + nums[i] >= end) {
                end = i;
            }
        }
        if (end == 0) {
            return true;
        } else {
            return false;
        }
    }
}

跳跃游戏 II

解法

class Solution {
    public int jump(int[] nums) {
        int max = 0, min = 0, maxs = 0;
        for (int i = 0; i < nums.length - 1; i++) {
            int x = nums[i] + i;
            if (x > max) {
                max = x;
            }
            if (maxs == i) {
                maxs = max;
                min++;
            }
        }
        return min;
    }
}

划分字母区间

解法

class Solution {
    public List<Integer> partitionLabels(String s) {
        int[] map = new int[26];
        for (int i = 0; i < s.length(); i++) {
            map[s.charAt(i) - 'a']++;
        }
        List<Integer> res = new ArrayList<>();
        int[] find = new int[26];
        int sum = 0;
        int total = 0;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
            char a = s.charAt(i);
            sb.append(a);
            if (find[a - 'a'] == 0) {
                sum++;
            }
            find[a - 'a']++;
            if (find[a - 'a'] == map[a - 'a']) {
                total++;
            }
            if (total == sum) {
                res.add(sb.length());
                total = 0;
                sum = 0;
                sb.setLength(0);
            }
        }
        return res;
    }
}

动态规划

走楼梯

解法

class Solution {
    public int climbStairs(int n) {
        int[] dp = new int[1001];
        return find(dp, n);
    }

    public int find(int[] dp, int n) {
        if (n == 1) {
            return 1;
        }
        if (n == 0) {
            return 1;
        }
        if (dp[n] != 0) {
            return dp[n];
        }
        dp[n] = find(dp, n - 1) + find(dp, n - 2);
        return dp[n];
    }
}

杨辉三角

解法

class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> res = new ArrayList<>();
        for (int i = 0; i < numRows; i++) {
            List<Integer> tes = new ArrayList<Integer>();
            tes.add(1);
            res.add(tes);
        }
        for (int i = 1; i < numRows; i++) {
            for (int j = 1; j <= i; j++) {
                if (j == i) {
                    res.get(i).add(1);
                } else {
                    int a = res.get(i - 1).get(j - 1);
                    int b = res.get(i - 1).get(j);
                    res.get(i).add(a + b);
                }
            }
        }
        return res;
    }
}

打家劫舍

解法

class Solution {
    public int rob(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        if (nums.length == 1) {
            return nums[0];
        }
        if (nums.length == 2) {
            return Math.max(nums[0], nums[1]);
        }
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        for (int i = 2; i < nums.length; i++) {
            dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[nums.length - 1];
    }
}

完全平方数

解法

class Solution {
    public int numSquares(int n) {
        int[] dp = new int[n + 1];
        for (int i = 0; i <= n; i++) {
            dp[i] = i;
            for (int j = 0; j * j <= i; j++) {
                dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
            }
        }
        return dp[n];
    }
}

零钱兑换

解法

class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] f = new int[amount + 1];
        Arrays.fill(f, Integer.MAX_VALUE / 2);
        f[0] = 0;
        for (int i = 0; i < coins.length; i++) {
            for (int j = coins[i]; j <= amount; j++) {
                f[j] = Math.min(f[j], f[j - coins[i]] + 1);
            }
        }
        return f[amount] < Integer.MAX_VALUE / 2 ? f[amount] : -1;
    }
}

单词拆分

解法

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        Set<String> wordDictSet = new HashSet(wordDict);
        boolean[] dp = new boolean[s.length() + 1];
        dp[0] = true;
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 0; j < i; j++) {
                if (dp[j] && wordDictSet.contains(s.substring(j, i))) {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[s.length()];
    }
}

最长递增子序列

解法

class Solution {
    public int lengthOfLIS(int[] nums) {
        int[] res = new int[nums.length];
        res[nums.length - 1] = 1;
        int max = 1;
        for (int i = nums.length - 2; i >= 0; i--) {
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[j] > nums[i]) {
                    if (res[i] < res[j] + 1) {
                        res[i] = res[j] + 1;
                    }
                }
            }
            if (res[i] == 0) {
                res[i] = 1;
            }
            if (res[i] > max) {
                max = res[i];
            }
        }
        return max;
    }
}

乘积最大子数组

解法

class Solution {
    public int maxProduct(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int[] max = new int[nums.length];
        int[] min = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            max[i] = nums[i];
            min[i] = nums[i];
        }
        for (int i = 1; i < nums.length; i++) {
            max[i] = Math.max(max[i - 1] * nums[i], Math.max(nums[i], min[i - 1] * nums[i]));
            min[i] = Math.min(min[i - 1] * nums[i], Math.min(nums[i], max[i - 1] * nums[i]));
        }
        int ans = max[0];
        for (int i = 1; i < nums.length; ++i) {
            ans = Math.max(ans, max[i]);
        }
        return ans;
    }
}

分割等和子集

解法

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        int n = nums.length;
        for (int num : nums) {
            sum = sum + num;
        }
        if (sum % 2 == 1) {
            return false;
        }
        int target = sum / 2;
        int[] dp = new int[target + 1];
        for (int i = 0; i < n; i++) {
            for (int j = target; j >= nums[i]; j--) {
                dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
            }
        }
        return dp[target] == target;
    }
}

最长有效括号

解法

class Solution {
    public int longestValidParentheses(String s) {
        int left = 0, right = 0, maxlength = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                left++;
            } else {
                right++;
            }
            if (left == right) {
                maxlength = Math.max(maxlength, 2 * right);
            } else if (right > left) {
                left = right = 0;
            }
        }
        left = right = 0;
        for (int i = s.length() - 1; i >= 0; i--) {
            if (s.charAt(i) == '(') {
                left++;
            } else {
                right++;
            }
            if (left == right) {
                maxlength = Math.max(maxlength, 2 * left);
            } else if (left > right) {
                left = right = 0;
            }
        }
        return maxlength;
    }
}

多维动态规划

不同路径

解法

class Solution {
    public int uniquePaths(int m, int n) {
        int[] f = new int[n];
        for (int i = 0; i < n; ++i) {
            f[i] = 1;
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                f[j] += f[j - 1];
            }
        }
        return f[n - 1];
    }
}

最小路径和

解法

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

最长回文子串

解法

class Solution {
    public String longestPalindrome(String s) {
        int max = 1;
        int beg = 0;
        int left, right;
        int n = s.length();
        for (int i = 0; i < n; i++) {
            left = i - 1;
            right = i + 1;
            while (left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
                if (max < right - left + 1) {
                    max = right - left + 1;
                    beg = left;
                }
                left--;
                right++;
            }
            left = i;
            right = i + 1;
            while (left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
                if (max < right - left + 1) {
                    max = right - left + 1;
                    beg = left;
                }
                left--;
                right++;
            }
        }
        return s.substring(beg, beg + max);
    }
}

最长公共子序列

解法

class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        char[] t = text2.toCharArray();
        int m = t.length;
        int[] f = new int[m + 1];
        for (char x : text1.toCharArray()) {
            int pre = 0;
            for (int j = 0; j < m; j++) {
                int tmp = f[j + 1];
                if (x == t[j]) {
                    f[j + 1] = pre + 1;
                } else {
                    f[j + 1] = Math.max(f[j + 1], f[j]);
                }
                pre = tmp;
            }
        }
        return f[m];
    }
}

编辑距离

解法

class Solution {
    public int minDistance(String word1, String word2) {
        int n = word1.length();
        int m = word2.length();
        int[][] dp = new int[n + 1][m + 1];
        for (int i = 0; i <= m; i++) {
            dp[0][i] = i;
        }
        for (int j = 0; j <= n; j++) {
            dp[j][0] = j;
        }
        for (int i = 1; i < n + 1; i++) {
            for (int j = 1; j < m + 1; j++) {
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
                    if (dp[i - 1][j - 1] < dp[i][j]) {
                        dp[i][j] = dp[i - 1][j - 1];
                    }
                } else {
                    dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
                    if (dp[i - 1][j - 1] + 1 < dp[i][j]) {
                        dp[i][j] = dp[i - 1][j - 1] + 1;
                    }
                }
            }
        }
        return dp[n][m];
    }
}

技巧

只出现一次的数字

解法:两两异或,相同的会变成 0,剩下的就是出现一次的。

class Solution {
    public int singleNumber(int[] nums) {
        int x = nums[0];
        if (nums.length == 0) {
            return x;
        }
        for (int i = 1; i < nums.length; i++) {
            x = x ^ nums[i];
        }
        return x;
    }
}

多数元素

解法

class Solution {
    public int majorityElement(int[] nums) {
        int ms = nums[0];
        int count = 1;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] == ms) {
                count++;
            } else {
                count--;
                if (count == 0) {
                    ms = nums[i];
                    count = 1;
                }
            }
        }
        return ms;
    }
}

颜色分类

解法

class Solution {
    public void sortColors(int[] nums) {
        int len = nums.length;
        if (len < 2) {
            return;
        }
        int beg = 0;
        int end = len - 1;
        int i = 0;
        while (i <= end) {
            if (nums[i] == 0) {
                swap(nums, beg, i);
                beg++;
                i++;
            } else if (nums[i] == 1) {
                i++;
            } else {
                swap(nums, i, end);
                end--;
            }
        }
    }

    public void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

下一个排列

解法

class Solution {
    public void nextPermutation(int[] nums) {
        int len = nums.length;
        for (int i = len - 1; i >= 1; i--) {
            if (nums[i - 1] < nums[i]) {
                reverse(nums, i, len - 1);
                for (int j = i; j < len; j++) {
                    if (nums[j] > nums[i - 1]) {
                        swap(nums, j, i - 1);
                        break;
                    }
                }
                break;
            }
            if (i == 1) {
                reverse(nums, 0, len - 1);
            }
        }
    }

    public void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }

    public void reverse(int[] nums, int left, int right) {
        while (left < right) {
            swap(nums, left++, right--);
        }
    }
}

寻找重复数

解法:快慢指针的做法,根据条件,元素的大小是不超过数组的长度的,那么也就会,出现重复数意味着出现环,那么就是采取回环链表的做法。

class Solution {
    public int findDuplicate(int[] nums) {
        int slow = 0;
        int fast = 0;
        while (true) {
            slow = nums[slow];
            fast = nums[nums[fast]];
            if (fast == slow) {
                break;
            }
        }
        fast = 0;
        while (true) {
            slow = nums[slow];
            fast = nums[fast];
            if (slow == fast) {
                return slow;
            }
        }
    }
}

目录

  1. LeetCode Hot 100 算法题解(Java 版)
  2. 哈希
  3. 两数之和
  4. 字母异位词分组
  5. 最长连续序列
  6. 双指针
  7. 移动零
  8. 盛最多水的容器
  9. 三数之和
  10. 接雨水
  11. 滑动窗口
  12. 无重复字符的最长子串
  13. 找到字符串中所有字母异位词
  14. 子串
  15. 和为 k 的子数组
  16. 滑动窗口最大值
  17. 最小覆盖子串
  18. 普通数组
  19. 最大子数组和
  20. 合并区间
  21. 轮转数组
  22. 除了自身以外数组的乘积
  23. 缺失的第一个正数
  24. 矩阵
  25. 矩阵置零
  26. 螺旋数组
  27. 旋转图像
  28. 搜索二维矩阵 II
  29. 链表
  30. 相交链表
  31. 反转链表
  32. 回文链表
  33. 环形链表
  34. 环形链表 II
  35. 合并两个有序链表
  36. 两数相加
  37. 删除链表的倒数第 N 个节点
  38. 两两交换链表中的节点
  39. K 个一组翻转链表
  40. 随机链表的复制
  41. 排序链表
  42. 合并 K 个升序链表
  43. LRU 缓存
  44. 二叉树
  45. 二叉树的中序遍历
  46. 二叉树的最大深度
  47. 翻转二叉树
  48. 对称二叉树
  49. 二叉树的直径
  50. 二叉树的层序遍历
  51. 将有序数组转换为二叉搜索树
  52. 验证二叉搜索树
  53. 二叉搜索树中第 K 小的元素
  54. 二叉树的右视图
  55. 二叉树展开为链表
  56. 从前序与中序遍历序列构造二叉树
  57. 路径总和 III
  58. 二叉树的最近公共祖先
  59. 二叉树的最大路径和
  60. 图论
  61. 岛屿数量
  62. 腐烂的橘子
  63. 课程表
  64. 实现前缀树
  65. 回溯
  66. 全排列
  67. 子集
  68. 电话号码的字母组合
  69. 组合总数
  70. 括号生成
  71. 单词搜索
  72. 分割回文串
  73. N 皇后
  74. 二分查找
  75. 搜索插入位置
  76. 搜索二维矩阵
  77. 在排序数组中查找元素的第一个和最后一个位置
  78. 搜索旋转排序数组
  79. 寻找旋转排序数组中的最小值
  80. 寻找两个正序数组的中位数
  81. 栈
  82. 有效的括号
  83. 最小栈
  84. 字符串解码
  85. 每日温度
  86. 柱状图中的最大的矩形
  87. 堆
  88. 数组中的第 K 个最大元素
  89. 前 K 个高频元素
  90. 数据流的中位数
  91. 贪心算法
  92. 买卖股票的最佳时机
  93. 跳跃游戏
  94. 跳跃游戏 II
  95. 划分字母区间
  96. 动态规划
  97. 走楼梯
  98. 杨辉三角
  99. 打家劫舍
  100. 完全平方数
  101. 零钱兑换
  102. 单词拆分
  103. 最长递增子序列
  104. 乘积最大子数组
  105. 分割等和子集
  106. 最长有效括号
  107. 多维动态规划
  108. 不同路径
  109. 最小路径和
  110. 最长回文子串
  111. 最长公共子序列
  112. 编辑距离
  113. 技巧
  114. 只出现一次的数字
  115. 多数元素
  116. 颜色分类
  117. 下一个排列
  118. 寻找重复数
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Llama 3-8B-Instruct 在昇腾 NPU 上的 SGLang 性能实测
  • WSL2 + Ubuntu 22.04 全流程安装与配置指南(适配 D 盘)
  • Xilinx FPGA ISERDES 使用详解
  • HTTP 网络协议核心概念解析
  • CANN 算子开发:Transformer 核心算子优化与 AIGC 实战
  • Luma AI Dream Machine 视频生成模型评测与使用指南
  • PX4 结合 Mid360 与 Fast-LIO 实现无人机室内定点悬停
  • Git 连接 GitHub 出现权限拒绝错误的解决方案
  • VMware Workstation 17 下 Ubuntu 24.04 虚拟机卡死问题排查与解决
  • Python 集合与列表性能对比:何时更快?
  • Flutter WebDriver 在 OpenHarmony 环境下的适配与实战
  • Docker Compose UI: 无需命令行管理容器及远程访问配置指南
  • JDK 17 下载与安装配置指南
  • Qt与Web混合编程:CEF与QCefView深度解析
  • 基于 Spring Cloud 的电商系统设计与实现:用户与商品模块
  • OpenClaw Java:基于 Spring Boot 的 AI Agent Gateway 全栈实践
  • LTX-2.3:开源音视频生成新标杆,单模型同步输出视频与音频
  • LIBERO 数据集详解:终身机器人学习与知识迁移基准
  • 初识 LangChain 与大语言模型基础
  • Java 包装类与泛型核心解析

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online