leetcode Top100题单

[1]两数之和 52.4% Easy 0.0%

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个
整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] ==
9 ,返回 [0, 1] 。 示例 2:

输入:nums = [3,2,4], target = 6 输出:[1,2] 示例 3:

输入:nums = [3,3], target = 6 输出:[0,1] 提示:

2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109 只会存在一个有效答案

本题是简单题,解题思路是设置一个map容器,记录value与索引的映射,对数组遍历。

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

[2]两数相加 41.6% Medium 0.0%

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。 输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8]
解释:342 + 465 = 807. 示例 2:

输入:l1 = [0], l2 = [0] 输出:[0] 示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] 输出:[8,9,9,9,0,0,0,1] 提示:

每个链表中的节点数在范围 [1, 100] 内 0 <= Node.val <= 9 题目数据保证列表表示的数字不含前导零

思路:逐一加和,不要忘记进位就行。
复杂度:n/n

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(-1);
        int flag = 0; // 进位标识
        ListNode cur = dummy;
        // 存在链表不为空,或者进位不为0
        while (l1 != null || l2 != null || flag != 0) {
            int sum = (l1 != null ? l1.val : 0) + (l2 != null ? l2.val : 0) + flag;
            cur.next = new ListNode(sum % 10);
            flag = sum / 10;
            cur = cur.next;
            l1 = l1 != null ? l1.next : null;
            l2 = l2 != null ? l2.next : null;
//            System.out.println(sum % 10 + " " + sum / 10);
        }

        return dummy.next;
    }
}

[3]无重复字符的最长子串 38.8% Medium 0.0%

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1: 输入: s = “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

刚开始刷leetcode Top题单,遇到的第一道滑动窗口题目,搞了很久。
滑动窗口,不断维护头尾指针位置和目标结果。
在这里插入图片描述
时间复杂度:主要是遍历了一次,n
空间复杂度:使用了HashMap,并放入了所有元素。n

class Solution {
    public int lengthOfLongestSubstring(String s) {
        // 容器,key为当前字符,value为字符索引
        Map<Character, Integer> map = new HashMap<>();
        int maxLength = 0;
        // 不断移动end指针位置,条件判断修改start位置
        for (int start = 0, end = 0; end < s.length(); end++) {
            char c = s.charAt(end);
            // 如果已有该字符,修改start位置
            if (map.containsKey(c)) {
                // map中数据不删除,因此只移动比start大的后1个位置
                start = Math.max(map.get(c) + 1, start);
            }
            // 更新结果
            maxLength = Math.max(maxLength, end - start + 1);
            map.put(c, end);
        }
        return maxLength;
    }
}

[4]寻找两个正序数组的中位数 41.4% Hard 0.0%

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2] 输出:2.00000 解释:合并数组 = [1,2,3] ,中位数 2 示例
2:

输入:nums1 = [1,2], nums2 = [3,4] 输出:2.50000 解释:合并数组 = [1,2,3,4] ,中位数 (2

    1. / 2 = 2.5 提示:

nums1.length == m nums2.length == n 0 <= m <= 1000 0 <= n <= 1000 1 <=
m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106 Related Topics 数组 二分查找 分治

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        // 奇数位[0,1][2,3,4],中位数是第3个
        // 偶数位[0,1][2,3,4,5],中位数是第3个和第4个加和作差。
        int m = nums1.length;
        int n = nums2.length;
        int left = (m + n + 1) / 2; // 第3个
        int right = (m + n + 2) / 2; // 第4个
        if (left == right) { // 此时为奇数
            return findth(nums1, 0, nums2, 0, left);
        } else {
            return (findth(nums1, 0, nums2, 0, left) + findth(nums1, 0, nums2, 0, right)) / 2.0;
        }
    }

    // 在[i, nums1.length -1],[j, nums2.length - 1] 范围找到第th个数
    private double findth(int[] nums1, int i, int[] nums2, int j, int k) {
        // 如果i/j大于等于数组长度,表示当前数组为空,直接从另一个数组取值即可。
        if (i >= nums1.length) return nums2[j + k - 1];
        if (j >= nums2.length) return nums1[i + k - 1];
        if (k == 1) return Math.min(nums1[i], nums2[j]);

        // 使用二分法找到第k/2个数
        int midVal1 = (i + k / 2 - 1 < nums1.length)
                ? nums1[i + k / 2 - 1] // nums1包含k/2个元素
                : Integer.MAX_VALUE;
        int midVal2 = (j + k / 2 - 1 < nums2.length)
                ? nums2[j + k / 2 - 1] // nums2包含k/2个元素
                : Integer.MAX_VALUE;
        // 从小到大逼近
        // 第k/2个元素必然小于第k个元素,因此[i, i + k / 2 - 1]可以排除了
        return midVal1 < midVal2
                ? findth(nums1, i + k / 2, nums2, j, k - k / 2)
                : findth(nums1, i, nums2, j + k / 2, k - k / 2);
    }
}

[5]最长回文子串 36.7% Medium 0.0%

[10]正则表达式匹配 31.6% Hard 0.0%

[11]盛最多水的容器 61.4% Medium 0.0%

[15]三数之和 35.5% Medium 0.0%

[17]电话号码的字母组合 57.8% Medium 0.0%

[19]删除链表的倒数第 N 个结点 44.0% Medium 0.0%

[20]有效的括号 44.5% Easy 0.0%

✔ [21]合并两个有序链表 66.7% Easy 0.0% 迭代、递归

当两个链表都不为空时,迭代判断大小,添加节点。一方为空,则直接补另一方剩下所有的节点。
时间复杂度取决于两个链表长度,O(m+n)。
空间复杂度小,只需要修改指针指向性,O(1)

class Solution {
    public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        // 判断头
        ListNode pre = new ListNode(-1);
        ListNode cur = pre;
        while (list1 != null && list2 != null) {
            if (list1.val <= list2.val) {
                cur.next = list1;
                list1 = list1.next;
                cur = cur.next;
            } else {
                cur.next = list2;
                list2 = list2.next;
                cur = cur.next;
            }
        }
        // 剩下的不循环
        cur.next = list1 != null ? list1 : list2;
        return pre.next;
    }
}

递归要考虑终止条件、子集等。终止条件,当某一个链表到达末尾,递归就可以结束了。
针对于子集,假设list1是1,2,4,list2是1,3,4,当递归一层后,子集变为list1=2,4,list2=1,3,4.

// 递归实现
class Solution {
    public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if(list1 == null) {
            return list2;
        }
        if(list2 == null) {
            return list1;
        }
        if(list1.val < list2.val) {
            list1.next = mergeTwoLists(list1.next, list2);
            return list1;
        } else {
            list2.next = mergeTwoLists(list1, list2.next);
            return list2;
        }
    }
}

✔ [23]合并K个升序链表 56.8% Hard 0.0% 优先队列、二分法
[31]下一个排列 37.9% Medium 0.0%
[32]最长有效括号 36.8% Hard 0.0%
[33]搜索旋转排序数组 43.7% Medium 0.0%
✔ [34]在排序数组中查找元素的第一个和最后一个位置 42.2% Medium 0.0%
[39]组合总和 72.7% Medium 0.0%
[42]接雨水 61.7% Hard 0.0%
[46]全排列 78.7% Medium 0.0%
[48]旋转图像 74.3% Medium 0.0%
[49]字母异位词分组 67.6% Medium 0.0%
✔ [53]最大子数组和 55.0% Easy 0.0%
✔ [55]跳跃游戏 43.5% Medium 0.0%
[56]合并区间 48.9% Medium 0.0%
✔ [62]不同路径 66.9% Medium 0.0%
[64]最小路径和 69.3% Medium 0.0%

✔ [70]爬楼梯 53.9% Easy 0.0% 动态规划

class Solution {
    // dp[i]表示i时的方法个数
    // 状态方程:dp[i] = dp[i - 1] + dp[i - 2]
    // 初始值:注意从1开始
    // 顺序:i依赖与i-1,i-2,从小到大执行
    // 示例推导
    public int climbStairs(int n) {
        if (n == 1 || n ==2){
            return n;
        }
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

[72]编辑距离 62.6% Hard 0.0%

[75]颜色分类	60.1%	Medium	0.0%
[76]最小覆盖子串	44.6%	Hard	0.0%
[78]子集	80.7%	Medium	0.0%
[79]单词搜索	46.4%	Medium	0.0%
[84]柱状图中最大的矩形	44.5%	Hard	0.0%
[85]最大矩形	53.6%	Hard	0.0%

✔ [94]二叉树的中序遍历 75.8% Easy 0.0% 深度优先遍历、递归、迭代

递归实现

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

    public void inorder(List<Integer> list, TreeNode cur) {
        if (cur == null) {
            return ;
        }
        inorder(list, cur.left);
        list.add(cur.val);
        inorder(list, cur.right);
    }
}

非递归遍历

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        // 边界
        if (root == null) {
            return list;
        }
        // 栈实现:不断将左侧节点入栈,然后再弹出结点,记录中点,并指向右节点
        TreeNode cur = root;
        Stack<TreeNode> stack = new Stack<>();
        // stack初始是空的,所以要加cur != null
        while(cur != null || !stack.isEmpty()) {
            if (cur != null) {
                stack.push(cur);
                cur = cur.left;
            } else {
                cur = stack.pop();
                list.add(cur.val);
                cur = cur.right;
            }
        }
        return list;
    }

}

✔ [96]不同的二叉搜索树 70.6% Medium 0.0%
[98]验证二叉搜索树 36.4% Medium 0.0%
✔ [101]对称二叉树 57.5% Easy 0.0%
[102]二叉树的层序遍历 65.0% Medium 0.0%
✔ [104]二叉树的最大深度 76.9% Easy 0.0%
[105]从前序与中序遍历序列构造二叉树 71.2% Medium 0.0%
[114]二叉树展开为链表 72.9% Medium 0.0%
[121]买卖股票的最佳时机 58.1% Easy 0.0%
[124]二叉树中的最大路径和 45.2% Hard 0.0%
✔ [128]最长连续序列 55.1% Medium 0.0%
[136]只出现一次的数字 72.2% Easy 0.0%
[139]单词拆分 53.5% Medium 0.0%
✔ [141]环形链表 51.5% Easy 0.0%

[128]最长连续序列 54.9% Medium 0.0%

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入:nums = [100,4,200,1,3,2] 输出:4 解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:

输入:nums = [0,3,7,2,5,8,4,6,0,1] 输出:9 提示:

0 <= nums.length <= 105
-109 <= nums[i] <= 109 Related Topics 并查集 数组 哈希表

解题思想:
题目要求o(n),排序是不好使了。
借助set的查询能力,遍历set找到序列的头部,从头部顺序找到能达到的最长序列。
复杂度:n/n。

class Solution {
    public int longestConsecutive(int[] nums) {
        // set容器:去重,借助哈希的查询速率
        Set<Integer> set = new HashSet<>();
        for (int num : nums) {
            set.add(num);
        }

        // 记录最大连续长度
        int maxlength = 0;

        // 遍历每个数字
        for(int num : set) {
            // 如果包含num-1,说明当前数字不是连续序列的头部,跳过
            if(set.contains(num - 1)) {
                continue;
            }
            // 此时当前节点是一个序列首个数
            int sequenceLength = 1;
            int curNum = num;
            while(set.contains(curNum + 1)) {
                curNum++;
                sequenceLength++;
            }
            maxlength = Math.max(maxlength, sequenceLength);
        }

        return maxlength;
    }
}

✔ [141]环形链表 51.4% Easy 0.0%
✔ [142]环形链表 II 55.9% Medium 0.0%
✔ [152]乘积最大子数组 42.5% Medium 0.0%
✔ [206]反转链表 72.8% Easy 0.0%
✔ [226]翻转二叉树 79.1% Easy 0.0% 递归、层序迭代遍历思想
✔ [322]零钱兑换 45.4% Medium 0.0%
✔ [347]前 K 个高频元素 62.8% Medium 0.0% 优先队列、排序
✔ [617]合并二叉树 78.9% Easy 0.0% 递归遍历求值
✔ [647]回文子串 66.2% Medium 0.0% 暴力求解、动态规划【待补充】

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值