1. 两数之和

  1. class Solution {
  2. public int[] twoSum(int[] nums, int target) {
  3. int[] ints = new int[2];
  4. for (int i = 0; i < nums.length; i++) {
  5. for (int j = i + 1; j < nums.length; j++) {
  6. if (target == nums[i] + nums[j]) {
  7. ints[0] = i;
  8. ints[1] = j;
  9. return ints;
  10. }
  11. }
  12. }
  13. return ints;
  14. }
  15. }
  1. class Solution {
  2. public int[] twoSum(int[] nums, int target) {
  3. int[] ints = new int[2];
  4. HashMap<Integer, Integer> hashMap = new HashMap<>();
  5. hashMap.put(nums[0], 0);
  6. for (int i = 1; i < nums.length; i++) {
  7. Integer value = hashMap.get(target - nums[i]);
  8. if (value != null) {
  9. ints[0] = i;
  10. ints[1] = value;
  11. return ints;
  12. }
  13. hashMap.put(nums[i], i);
  14. }
  15. return ints;
  16. }
  17. }

2. 两数相加

  1. class Solution {
  2. public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
  3. ListNode cur1 = l1;
  4. ListNode cur2 = l2;
  5. // 虚拟头节点
  6. ListNode dummy = new ListNode();
  7. ListNode current = dummy;
  8. // 用来表示进位
  9. int carry = 0;
  10. while (cur1 != null || cur2 != null) {
  11. int val1 = (cur1 == null) ? 0 : cur1.val;
  12. int val2 = (cur2 == null) ? 0 : cur2.val;
  13. int sum = val1 + val2 + carry;
  14. current.next = new ListNode(sum % 10);
  15. current = current.next;
  16. carry = sum / 10;
  17. if (cur1 != null) {
  18. cur1 = cur1.next;
  19. }
  20. if (cur2 != null) {
  21. cur2 = cur2.next;
  22. }
  23. }
  24. if (carry != 0) {
  25. current.next = new ListNode(carry);
  26. }
  27. return dummy.next;
  28. }
  29. }

3. 无重复字符的最长子串

窗口内是什么:无重复字符的字串
如何移动窗口的起始位置:当窗口 [i, j] 右边界的下一个字符存在窗口内,则窗口的起始位置变为 重复字符的下一个索引
如何移动窗口的结束位置:当窗口 [i, j] 右边界的下一个字符不存在窗口内,则窗口的结束位置 j + 1

  1. class Solution {
  2. String s;
  3. public int lengthOfLongestSubstring(String s) {
  4. this.s = s;
  5. // 定义窗口的边界
  6. int winStart = 0;
  7. int winEnd = 0;
  8. // 定义一组和窗口有关的状态
  9. int result = 0;
  10. while (winEnd < s.length()) {
  11. // 判断下标位置 winEnd 的字符是否重复出现在窗口 [winStart, winEnd] 内
  12. int index = judge(winStart, winEnd);
  13. if (index != -1) {
  14. winStart = index + 1;
  15. } else {
  16. result = Math.max(result, winEnd - winStart + 1);
  17. winEnd++;
  18. }
  19. }
  20. return result;
  21. }
  22. // 这个判断的逻辑可以用哈希表优化到 O(1)
  23. // 判断下标位置 winEnd 的字符是否重复出现在窗口 [winStart, winEnd] 内
  24. // 如果没有重复出现,返回 -1;如果有重复出现,返回重复出现的下标
  25. private int judge(int winStart, int winEnd) {
  26. for (int i = winStart; i < winEnd; i++) {
  27. if (s.charAt(i) == s.charAt(winEnd)) {
  28. return i;
  29. }
  30. }
  31. return -1;
  32. }
  33. }
  1. class Solution {
  2. String s;
  3. public int lengthOfLongestSubstring(String s) {
  4. this.s = s;
  5. // 定义窗口的边界
  6. int winStart = 0;
  7. int winEnd = 0;
  8. // 定义一组和窗口有关的状态
  9. int result = 0;
  10. // key 为字符,value 为字符对于的下标
  11. HashMap charMap = new HashMap();
  12. while (winEnd < s.length()) {
  13. // 判断下标位置 winEnd 的字符是否重复出现在窗口 [winStart, winEnd] 内
  14. Integer value = (Integer) charMap.get(s.charAt(winEnd));
  15. if (value == null) {
  16. charMap.put(s.charAt(winEnd), winEnd);
  17. result = Math.max(result, winEnd - winStart + 1);
  18. winEnd++;
  19. } else {
  20. for (int i = winStart; i <= value; i++) {
  21. charMap.remove(s.charAt(i));
  22. }
  23. winStart = value + 1;
  24. }
  25. }
  26. return result;
  27. }
  28. }
class Solution {

    String s;

    public int lengthOfLongestSubstring(String s) {
        this.s = s;

        // 定义窗口的边界
        int winStart = 0;
        int winEnd = 0;

        // 定义一组和窗口有关的状态
        int result = 0;
        // key 为字符,value 为字符对于的下标
        HashMap charMap = new HashMap();

        while (winEnd < s.length()) {
            // 判断下标位置 winEnd 的字符是否重复出现在窗口 [winStart, winEnd] 内
            Integer value = (Integer) charMap.get(s.charAt(winEnd));

            if (value == null) {
                charMap.put(s.charAt(winEnd), winEnd);
                result = Math.max(result, winEnd - winStart + 1);
                winEnd++;
            } else {
                // 对上一个版本优化的地方(没有了 HashMap 移除的逻辑,时间复杂度更低)
                /*
                核心思想:
                    不移除新旧 winStart 之间的元素。若遍历出重复字符,则判断它的位置
                    若重复字符出现在 winStart 之前,说明该重复字符不在窗口内,窗口无需移动
                    若重复字符出现在 winStart 之后,说明该重复字符在窗口内,窗口需要移动
                 */
                winStart = Math.max(value + 1, winStart);
            }
        }
        return result;
    }
}

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

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if (nums1.length == 0) {
            if (nums2.length % 2 == 0) {
                double average = (nums2[nums2.length / 2 - 1] + nums2[nums2.length / 2]) / 2.0;
                return average;
            } else {
                return nums2[nums2.length / 2];
            }
        }
        if (nums2.length == 0) {
            if (nums1.length % 2 == 0) {
                double average = (nums1[nums1.length / 2 - 1] + nums1[nums1.length / 2]) / 2.0;
                return average;
            } else {
                return nums1[nums1.length / 2];
            }
        }

        // 将两数组合并为一个有序数组
        int sum = nums1.length + nums2.length;
        int[] nums = new int[sum];
        int a1 = 0;
        int a2 = 0;
        int temp = 0;

        while (a1 < nums1.length && a2 < nums2.length) {
            if (nums1[a1] <= nums2[a2]) {
                nums[temp++] = nums1[a1++];
            } else {
                nums[temp++] = nums2[a2++];
            }
        }

        while (a1 < nums1.length) {
            nums[temp++] = nums1[a1++];
        }

        while (a2 < nums2.length) {
            nums[temp++] = nums2[a2++];
        }

        if (nums.length % 2 == 0) {
            double average = (nums[nums.length / 2 - 1] + nums[nums.length / 2]) / 2.0;
            return average;
        } else {
            return nums[nums.length / 2];
        }
    }
}

该题没有达到最小时间复杂度。

5.最长回文子串

class Solution {
    public String longestPalindrome(String s) {
        int startIndex = 0;
        int endIndex = 0;

        for (int i = 0; i < s.length(); i++) {
            int length1 = expandAroundCenter(s, i, i);
            int length2 = expandAroundCenter(s, i, i + 1);
            int maxLength = Math.max(length1, length2);
            if (maxLength > (endIndex - startIndex + 1)) {
                startIndex = i - (maxLength - 1) / 2;
                endIndex = i + maxLength / 2;
            }
        }
        return s.substring(startIndex, endIndex + 1);
    }

    private int expandAroundCenter(String s, int left, int right) {
        int lTemp = left;
        int rTemp = right;
        while (lTemp >= 0 && rTemp < s.length() && s.charAt(lTemp) == s.charAt(rTemp)) {
            lTemp--;
            rTemp++;
        }

        return rTemp - lTemp - 1;
    }
}
class Solution {
    public String longestPalindrome(String s) {
        int startIndex = 0;
        int endIndex = 0;

        // dp[i][j]的含义:用 dp[i][j] 的值来标记下标i到下标j构成的子字符串是否为回文串,是回文串值为 1,不是值为 0
        boolean[][] dp = new boolean[s.length()][s.length()];

        // 确定递推方程 dp[i][j] = dp[i + 1][j - 1] && (s.charAt(i) == s.charAt(j))

        // dp 数组初始化
        for (int i = 0; i < s.length(); i++) {
            dp[i][i] = true;
        }

        for (int i = s.length() - 1; i >= 0; i--) {
            for (int j = i; j < s.length(); j++) {
                // 处理特殊情况
                dp[i][j] = (j - i < 2 || dp[i + 1][j - 1]) && (s.charAt(i) == s.charAt(j));

                if (dp[i][j] && j - i + 1 > endIndex - startIndex + 1) {
                    startIndex = i;
                    endIndex = j;
                }
            }

        }
        return s.substring(startIndex, endIndex + 1);
    }
}

7. 整数反转

class Solution {
    public int reverse(int x) {
        int result = 0;

        while (x != 0) {
            if (result > Integer.MAX_VALUE / 10 || result < Integer.MIN_VALUE / 10) {
                return 0;
            }
            int num = x % 10;
            result = result * 10 + num;
            x /= 10;
        }
        return result;
    }
}

8. 字符串转换整数 (atoi)

10. 正则表达式匹配

11. 盛最多水的容器

13. 罗马数字转整数

14. 最长公共前缀

15. 三数之和

17. 电话号码的字母组合

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

20. 有效的括号

21. 合并两个有序链表

22. 括号生成

23. 合并K个升序链表

26. 删除有序数组中的重复项

28. 实现 strStr()

29. 两数相除

33. 搜索旋转排序数组

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

36. 有效的数独

38. 外观数列

41. 缺失的第一个正数

42. 接雨水

44. 通配符匹配

46. 全排列

48. 旋转图像

49. 字母异位词分组

50. Pow(x, n)

53. 最大子数组和

54. 螺旋矩阵

55. 跳跃游戏

56. 合并区间

62. 不同路径

66. 加一

69. x 的平方根

70. 爬楼梯

73. 矩阵置零

75. 颜色分类

76. 最小覆盖子串

78. 子集

79. 单词搜索

84. 柱状图中最大的矩形

88. 合并两个有序数组

91. 解码方法

94. 二叉树的中序遍历

98. 验证二叉搜索树