leetcode刷题记录

热题top100

1.两数之和

原题地址
给定一个整数数组 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

只会存在一个有效答案


 public static int[] twoSum(int[] nums, int target) {
        // 将元数据存储到 map 中 key:元数据值,value:元数据数组下标
        // 再次遍历元数据数组 找到 map-key = target - cur-key
        Map<Integer, List<Integer>> dataMap = new HashMap<>(nums.length);

        for (int i = 0; i < nums.length; i++) {
            if (dataMap.containsKey(nums[i])) {
                List<Integer> indexList = dataMap.get(nums[i]);
                indexList.add(i);
            } else {
                List<Integer> indexList = new ArrayList<>();
                indexList.add(i);
                dataMap.put(nums[i], indexList);
            }

        }

        for (int i = 0; i < nums.length; i++) {
            Integer search = target - nums[i];
            if (dataMap.containsKey(search)) {
                List<Integer> list = dataMap.get(search);
                for (Integer index : list) {
                    if (index != i) {
                        return new int[]{i, index};
                    }
                }
            }
        }
        return new int[]{};
    }
    

刷题记录:

  • 2022-03-20 二刷(一遍过)

2.两数相加

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

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

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:
在这里插入图片描述

输入: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
题目数据保证列表表示的数字不含前导零

Java代码

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode first = l1;
        ListNode second = l2;
        ListNode ans = new ListNode();
        ListNode result = ans;
        int multi = 0;
        while (first != null || second != null) {
            if (first == null) {
                int sum = second.val + multi;
                multi = sum / 10;

                result.next = new ListNode(sum % 10);
                result = result.next;
                second = second.next;
                continue;
            }

            if (second == null) {
                int sum = first.val + multi;
                multi = sum / 10;

                result.next = new ListNode(sum % 10);
                result = result.next;
                first = first.next;
                continue;
            }

            int sum = first.val + second.val + multi;
            multi = sum / 10;

            result.next = new ListNode(sum % 10);
            result = result.next;
            first = first.next;
            second = second.next;
        }

        if (multi != 0){
            result.next = new ListNode(multi);
        }

        return ans.next;
    }

刷题记录

  • 2022-03-20 二刷 一遍过,没看题解

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

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

示例 1:

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

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。

请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

提示:

0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成

    public static int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> dataMap = new HashMap<>();
        char[] chars = s.toCharArray();

        // 循环下标开始
        int search = 0;
        int begin = 0;
        int end = 0;
        int ans = 0;

        while (search < chars.length) {
            if (dataMap.containsKey(chars[search])) {
                ans = Math.max(end - begin, ans);

                search = dataMap.get(chars[search]) + 1;
                end = search;
                begin = search;
                dataMap.clear();
                continue;
            }
            dataMap.put(chars[search], search);
            search++;
            end++;
        }

        ans = Math.max(end - begin, ans);

        return ans;
    }

刷题记录

  • 2022-03-20 二刷 (没看题解)

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

原题地址
给定两个大小分别为 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 + 3) / 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
package xyz.fudongyang.review;

import java.util.PriorityQueue;

/**
 * @author: fudy
 * @date: 2022/3/20 上午 10:59
 * @Decription:
 **/
public class Lc_4 {
    public static void main(String[] args) {
        int[] nums1 = {0,0,0,0,0};
//        int[] nums1 = {1, 3};
        int[] nums2 = {-1,0,0,0,0,0,1};
//        int[] nums2 = {2};
        System.out.println("findMedianSortedArrays(nums1, nums2) = " + findMedianSortedArrays(nums1, nums2));
    }

    public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        // 维护两个优先级队列  一个大顶堆 一个小顶堆
        PriorityQueue<Integer> minQueue = new PriorityQueue<>(((o1, o2) -> o2 - o1));
        PriorityQueue<Integer> maxQueue = new PriorityQueue<>();

        // 放入数据 保证大顶堆 小顶堆的数量是一致的
        addQueue(minQueue, maxQueue, nums1);
        addQueue(minQueue, maxQueue, nums2);

        // 如果哪个数据比较多  拿哪个堆顶  如果一样多  则取两个堆顶的中间值
        if (maxQueue.size() == 0 && minQueue.size() == 0) {
            return 0;
        }
        if (minQueue.size() == maxQueue.size()) {
            return (double) (minQueue.peek() + maxQueue.peek()) / 2;
        }

        if (minQueue.size() > maxQueue.size()) {
            return minQueue.peek();
        } else {
            return maxQueue.peek();
        }
    }

    private static void addQueue(PriorityQueue<Integer> minQueue, PriorityQueue<Integer> maxQueue, int[] nums1) {
        for (int i : nums1) {
            if (minQueue.size() >= maxQueue.size()) {
                minQueue.add(i);
                maxQueue.add(minQueue.poll());
            } else {
                maxQueue.add(i);
                minQueue.add(maxQueue.poll());
            }
        }
    }
}

解题记录:

  • 2022-03-20 二刷,还是没做出来 看题解做出来了,需要三刷

5.最长回文子串

原题地址
给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

提示:

1 <= s.length <= 1000
s 仅由数字和英文字母组成

解题思路 都在代码注释里

public static String longestPalindrome(String s) {
        // 如果长度为1 直接返回
        int length = s.length();
        if (length == 1) {
            return s;
        }

        // 构建 dp 数组 数组的一维成为 i,二维称为j 代表着 i到j之间是不是回文子串 也就是 i 和 j代表着 字符在字符串的下标位置
        boolean[][] dp = new boolean[length][length];
        char[] chars = s.toCharArray();

        // 记录回文串的最大长度 初始化为1 因为字符本身也是回文串
        int maxLen = 1;
        // 记录回文串最大长度的开始下标 ,为了方便截取结果
        int beginIndex = 0;

        // 1、显然 i=j 时,肯定是字符串 因为单个字符本身就是回文子串,于是我们可以构建 dp 数组如下
        for (int i = 0; i < length; i++) {
            dp[i][i] = true;
        }

        // 我们只需要考虑 i在左边 j在右边的情况 即 i <= j 的情况,因为i = j的情况 我们在1的时候已经考虑过了,只需要考虑 i < j的情况
        for (int m = 1; m <= length; m++) {
            for (int i = 0; i < length; i++) {
                int j = i + m;

                if (j >= length) {
                    break;
                }

                // 2.如果 i位置 和 j位置 不相等 则他们之间肯定不是回文子串
                if (chars[i] != chars[j]) {
                    dp[i][j] = false;
                } else {
                    // 3.如果i位置 和 j位置相等,且中间最多只隔了一个字符 则肯定时回文串
                    if (j - i <= 2) {
                        dp[i][j] = true;
                    } else {
                        // 4.如果 中间隔了好几个字符 需要判断这几个字符是否是回文串
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                // 如果是最大的回文子串  则记录开始位置 偏移量
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    beginIndex = i;
                }
            }
        }
        return s.substring(beginIndex, beginIndex + maxLen);
    }

刷题记录:

  • 2022-03-20,二刷,看了代码才做出来

10.正则表达式(不推荐做)

原题地址

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

示例 1:

输入:s = "aa", p = "a"
输出:false

解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa", p = "a*"
输出:true

解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。

示例 3:

输入:s = "ab", p = ".*"
输出:true

解释:".*" 表示可匹配零个或多个('*')任意字符('.')。

提示:

1 <= s.length <= 20
1 <= p.length <= 30
s 只包含从 a-z 的小写字母。
p 只包含从 a-z 的小写字母,以及字符 . 和 *。
保证每次出现字符 * 时,前面都匹配到有效的字符

Java代码

package xyz.fudongyang.classic;

/**
 * @author: fudy
 * @date: 2022/3/8 下午 10:23
 * @Decription:
 **/
public class Lc_10_test {
    public static void main(String[] args) {
        String s = "abba";
        String p = "ab*a";
        System.out.println(isMatch(s, p));
    }

    public static boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();

        boolean[][] dp = new boolean[m + 1][n + 1];
        dp[0][0] = true;

        for (int i = 0; i < m + 1; i++) {
            for (int j = 1; j < n + 1; j++) {
                // 如果 p-1 等于 *
                if (p.charAt(j - 1) == '*') {
                    // 判断 dp 等于 dp[i][j-2] 如果 p-1等于 j 则舍弃 不等于 则 丢掉 i-1
                    dp[i][j] = dp[i][j - 2];
                    if (match(s, p, i, j - 1)) {
                        dp[i][j] = dp[i][j] || dp[i - 1][j];
                    }
                } else {
                    // P-1 不等于 * 进行 常规字符判断
                    if (match(s, p, i, j)) {
                        dp[i][j] = dp[i - 1][j - 1];
                    }
                }

            }
        }

        return dp[m][n];
    }

    private static boolean match(String s, String p, int m, int n) {
        if (m == 0) {
            return false;
        }
        if (p.charAt(n - 1) == '.') {
            return true;
        }
        return s.charAt(m - 1) == p.charAt(n - 1);
    }
}


解题记录:

  • 2022.03.08 看了好久的题解 比较绕

11. 盛最多水的容器

原题地址

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

示例 1:

在这里插入图片描述

输入:[1,8,6,2,5,4,8,3,7]
输出:49 

解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:

输入:height = [1,1]
输出:1

提示:

n == height.length
2 <= n <= 105
0 <= height[i] <= 104

双指针代码

public class Lc_5 {
    public static void main(String[] args) {
        int[] arr = {1, 8, 6, 2, 5, 4, 8, 3, 7};
        System.out.println(maxArea(arr));
    }

    public static int maxArea(int[] height) {
        int l = 0, r = height.length - 1;
        int ans = Integer.MIN_VALUE;
        while (l < r) {
            int areas = Math.min(height[l], height[r]) * (r - l);
            ans = Math.max(ans, areas);
            if (height[l] <= height[r]) {
                ++l;
            } else {
                --r;
            }
        }
        return ans;
    }
}

练习记录

  • 第一次练习时间:2022.02.08 09:44 pm
  • 第二次练习时间:2022-03-20 一遍过

15:三数之和

原题链接
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]

提示:

0 <= nums.length <= 3000
-105 <= nums[i] <= 105

Java代码

package xyz.fudongyang.classic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author: fudy
 * @date: 2022/2/28 下午 09:47
 * @Decription:
 **/
public class Lc_15 {
    public static void main(String[] args) {
        int[] arr = {-1, 0, 1, 2, -1, -4};
        System.out.println(threeSum(arr));
    }

    public static List<List<Integer>> threeSum(int[] nums) {
        int n = nums.length;
        // 先给数组排序
        Arrays.sort(nums);
        List<List<Integer>> ans = new ArrayList<>();

        for (int first = 0; first < n; first++) {

            // 如果不是第一个 需要判断是否和前一个相同 如果相同则不需要重复枚举了
            if (first > 0 && nums[first] == nums[first - 1]) {
                continue;
            }

            // c的指针始终是数组的右边界
            int third = n - 1;
            // 这是目标值
            int target = -nums[first];

            for (int second = first + 1; second < n; second++) {
                // 同样的 如果b枚举 也不能相同 相同就不需要重复枚举了
                if (second > first + 1 && nums[second] == nums[second - 1]) {
                    continue;
                }

                // 右侧是最大值 如果b+c小于等于目标值 或者 两个坐标相撞了 就退出
                while (second < third && nums[second] + nums[third] > target) {
                    --third;
                }

                // 坐标相撞情况
                if (second == third) {
                    break;
                }

                // 目标值
                if (nums[second] + nums[third] == target) {
                    List<Integer> data = new ArrayList<>(3);
                    data.add(nums[first]);
                    data.add(nums[second]);
                    data.add(nums[third]);
                    ans.add(data);
                }
            }
        }

        return ans;
    }
}

  • 第一次练习时间:2022/2/28 下午 09:47
  • 第二次练习时间:2022-03-20

17.电话号码的字母组合

原题链接
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

在这里插入图片描述

示例 1:

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

示例 2:

输入:digits = ""
输出:[]

示例 3:

输入:digits = "2"
输出:["a","b","c"]

提示:

0 <= digits.length <= 4
digits[i] 是范围 ['2', '9'] 的一个数字。

Java代码

package xyz.fudongyang.classic;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author: fudy
 * @date: 2022/3/1 下午 08:08
 * @Decription:
 **/
public class Lc_17 {

    public static void main(String[] args) {
        System.out.println(letterCombinations("23"));
    }

    private static List<String> letterCombinations(String digits) {
        List<String> combinations = new ArrayList<>();
        if (digits == null || digits.length() == 0){
            return combinations;
        }

        // 封装元数据
        final Map<Character, String> phoneMap = new HashMap<Character, String>() {{
            put('2',"abc");
            put('3',"def");
            put('4',"hlj");
            put('5',"abc");
            put('6',"abc");
            put('7',"abc");
            put('8',"abc");
            put('9',"abc");
        }};

        // 进行递归回溯
        backtrack(combinations,phoneMap,digits,0,new StringBuffer(digits.length()));

        return combinations;
    }

    private static void backtrack(List<String> combinations,Map<Character,String> phoneMap,String digits,int index,StringBuffer combination){
        // 临界值
        if (index == digits.length()){
            combinations.add(combination.toString());
            return;
        }

        // 递归循环 数字的位数
        char digit = digits.charAt(index);
        String letters = phoneMap.get(digit);

        // for循环 数字对应的字符
        for (int i = 0; i < letters.length(); i++) {
            char c = letters.charAt(i);
            combination.append(c);
            backtrack(combinations,phoneMap,digits,index+1,combination);
            combination.deleteCharAt(index);
        }

    }

}


  • 一刷时间:2022.03.01

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

原题链接
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

在这里插入图片描述

示例 1:

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1]

提示:

链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz

进阶:你能尝试使用一趟扫描实现吗?

Java代码(没看题解,自己一遍过,太帅了)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if(head == null){
            return head;
        }

        Map<Integer,ListNode> metaData = new HashMap<Integer,ListNode>();
        ListNode data = head;
        int count = 0;
        while(data != null){
            metaData.put(count++,data);
            data = data.next;
        }

        int index = count - n;
        if(index < 0){
            return null;
        }else if(index == 0){
            // 如果删除头节点
            return head.next;
        }else{
            // 如果删除中间节点
            ListNode preData = metaData.get(--index);
            if(index+2<count){
                preData.next = metaData.get(index+2);
            }else{
                preData.next = null;
            }
            return head;
        }


    }
}

-2022.03.01(自己解题 一遍过 太开心啦)

21.合并两个有序的链表

原题链接
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

在这里插入图片描述

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列

Java代码:一遍过 真的太爽了 终于不看题解可以做出来题啦


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if(list1 == null){
            return list2;
        }
        if(list2 == null){
            return list1;
        }

        ListNode head = new ListNode();

        ListNode first = list1;
        ListNode second = list2;
        // 先把最原始的指针对象存起来
        ListNode ans = head;
        while(first != null && second != null){
            ListNode next = new ListNode();
            head.next = next;
            if(first.val <= second.val){
                next.val = first.val;
                first = first.next;
            }else{
                next.val = second.val;
                second = second.next;
            }
            head = head.next;
        }

        if(first != null){
            head.next = first;
        }

        if(second != null){
            head.next = second;
        }

        return ans.next;
    }
}
  • 不看题解,一遍通过,太爽了 2022.03.01

22.括号生成

原题地址
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入:n = 1
输出:["()"]

提示:

1 <= n <= 8

Java代码


class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> ans = new ArrayList<>();

        backtrace(ans,new StringBuilder(),0,0,n);
        return ans;
    }

    private void backtrace(List<String> ans,StringBuilder stringBuilder,int open,int close,int max){
        if(stringBuilder.length() >= 2*max){
            ans.add(stringBuilder.toString());
            return;
        }

        if(open < max){
            stringBuilder.append('(');
            backtrace(ans,stringBuilder,open+1,close,max);
            stringBuilder.deleteCharAt(stringBuilder.length()-1);
        }

        if(close < open){
            stringBuilder.append(')');
            backtrace(ans,stringBuilder,open,close+1,max);
            stringBuilder.deleteCharAt(stringBuilder.length()-1);
        }
    }
}

解题时间:

  • 2022.03.07 10:03 pm

23.合并k个升序列表

原题地址
给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]

解释:链表数组如下:

[
  1->4->5,
  1->3->4,
  2->6
]

将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

提示:

k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4

Java代码

package xyz.fudongyang.classic;


import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class Lc_23 {

    public static void main(String[] args) {
        ListNode[] lists = new ListNode[5];
        lists[0] = new ListNode(1, new ListNode(4, new ListNode(5)));
        lists[1] = new ListNode(1, new ListNode(3, new ListNode(4)));
        lists[2] = new ListNode(2, new ListNode(6));
        System.out.println(mergeKLists(lists));
    }


    public static ListNode mergeKLists(ListNode[] lists) {
        // 暴力递归法
        // 总体思路:循环遍历所有的升序链表,do for while 设置空指针标志位为退出条件 第一次for循环 遍历所有的数据 找到最小值 并记录下标  作为下一次进行
        // TreeMap用来收集数据 key:数值 value:数组中的下标
        ListNode ans = new ListNode();
        ListNode temp = ans;
        TreeMap<Integer, List<Integer>> tempMap = new TreeMap<>();

        for (int i = 0; i < lists.length; i++) {
            if (lists[i] != null) {
                addElement(lists, tempMap, i);
            }
        }

        while (!tempMap.isEmpty()) {
            Map.Entry<Integer, List<Integer>> entry = tempMap.pollFirstEntry();
            Integer key = entry.getKey();
            List<Integer> values = entry.getValue();
            for (Integer value : values) {
                temp.next = new ListNode(key);
                temp = temp.next;
                if (lists[value] != null) {
                    addElement(lists, tempMap, value);
                }
            }
        }
        return ans.next;
    }

    private static void addElement(ListNode[] lists, TreeMap<Integer, List<Integer>> tempMap, int idx) {
        if (tempMap.containsKey(lists[idx].val)) {
            List<Integer> list = tempMap.get(lists[idx].val);
            list.add(idx);
        } else {
            List<Integer> list = new ArrayList<>();
            list.add(idx);
            tempMap.put(lists[idx].val, list);
        }
        lists[idx] = lists[idx].next;
    }
}



解题记录:

  • 20220313 直接一遍过(太开心了 这是自己直接ac的hard)

31:下一个排列

原题地址
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。

  • 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。

整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。

  • 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
  • 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
  • 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。

给你一个整数数组 nums ,找出 nums 的下一个排列。

必须 原地 修改,只允许使用额外常数空间。

示例 1:

输入:nums = [1,2,3]
输出:[1,3,2]

示例 2:

输入:nums = [3,2,1]
输出:[1,2,3]

示例 3:

输入:nums = [1,1,5]
输出:[1,5,1]

提示:

1 <= nums.length <= 100
0 <= nums[i] <= 100
class Solution {
 public static void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        // 从右到左 找到一个非升序的数当作较小值
        while (i >= 0 && nums[i] >= nums[i + 1]) {
            i--;
        }
        // 如果存在较小值,则从右到左,找到一个大于较小值的数当作较大值
        if (i >= 0) {
            int j = nums.length - 1;
            while (j >= 0 && nums[j] <= nums[i]) {
                j--;
            }
            // 替换较小值 较大值
            swap(nums, i, j);
        }
        // i 后面的数 应该从降序变为升序
        reverse(nums, i + 1);
    }

    private static void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    private static void reverse(int[] nums, int start) {
        int end = nums.length - 1;
        while (start < end) {
            swap(nums, start, end);
            start++;
            end--;
        }
    }
}

刷题记录:

  • 2022.03.16-看了题解一个小时才做出来

32: 最长的有效括号

原题地址
给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

示例 1:

输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"

示例 2:

输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"

示例 3:

输入:s = ""
输出:0

提示:

0 <= s.length <= 3 * 104
s[i] 为 '(' 或 ')'

Java代码(栈)

package xyz.fudongyang.review;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * @author: fudy
 * @date: 2022/3/21 下午 08:17
 * @Decription:
 **/
public class Lc_32 {
    public static void main(String[] args) {
        System.out.println(longestValidParentheses("()(()"));
    }

    public static int longestValidParentheses(String s) {
        char left = '(';
        char[] chars = s.toCharArray();

        Deque<Integer> deque = new ArrayDeque<>();
        int maxLen = 0;

        // 1. i 和 j 之间有几位 = i - j + 1 所以 我们先放入一个-1 到时候 减这个-1等于加一
        deque.addLast(-1);
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == left) {
                deque.addLast(i);
            } else {
                deque.pollLast();
                if (deque.isEmpty()) {
                    // 2.和1。一样 我们先放入 i的前一个元素 
                    deque.push(i);
                } else {
                    maxLen = Math.max(maxLen, i - deque.peekLast());
                }
            }
        }

        return maxLen;

    }

}

Java代码:动态规划

package xyz.fudongyang.review;

/**
 * @author: fudy
 * @date: 2022/3/21 下午 09:02
 * @Decription:
 **/
public class Lc_32_dp {
    public static void main(String[] args) {
        System.out.println(longestValidParentheses("()(()"));
    }

    // 有效括号的最长长度
    // 子串问题:严格以每个结尾计算个答案,最终答案必在其中
    public static int longestValidParentheses(String s) {
        if (s == null || s.length() < 2) {
            return 0;
        }

        int[] dp = new int[s.length()]; // dp[i]:严格以i位置结尾,形成的有效括号子串最长长度是多少
        int max = 0; // 最终的答案

        // dp[0] = 0; // 默认

        for (int i = 1; i < s.length(); i++) {
            // if (s.charAt(i) == '(') dp[i] = 0; 以左括号结尾,无效

            if (s.charAt(i) == ')') {
                int preLen = dp[i - 1]; // 前面已经形成的有效括号长度
                int pre = i - 1 - preLen; // 寻找与当前的右括号相匹配的左括号位置:前面有效括号长度再往前一个位置

                if (pre >= 0 && s.charAt(pre) == '(') { // 如果寻找到左括号:前面有效括号长度再往前一个位置是左括号
                    dp[i] = dp[i-1] + 2; // 可以与当前的右括号闭合,有效长度增加2

                    // 【注意】此时,需要再往前看下,是否还有有效长度,如果有,合并过来
                    // 例如:"()(()())" 当前在计算最后一个位置时,dp[7]已经等于 dp[6]+2 = 4+2
                    // 但需要再往前看一眼,dp[1]还有有效长度,合并过来 dp[7] = 4+2+2
                    // 那是否还需要再往前看?
                    // 不需要了,因为,如果前面还有有效长度,其长度肯定已经合并到dp[2]上了
                    // 因此,每次只需要再往前多看一眼就可以
                    if (pre-1 >= 0) {
                        dp[i] += dp[pre-1];
                    }
                }

                max = Math.max(max, dp[i]); // 严格以每个结尾抓一个答案,最终答案必在其中
            }
        }

        return max;
    }
}

刷题记录:

  • 2022-03-21 一刷(思路对,但是没做出来,看的题解)

33.搜索旋转排序数组

原题地址
整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

示例 1:

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

示例 2:

输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1

示例 3:

输入:nums = [1], target = 0
输出:-1

提示:

1 <= nums.length <= 5000
-10^4 <= nums[i] <= 10^4
nums 中的每个值都 独一无二
题目数据保证 nums 在预先未知的某个下标上进行了旋转
-10^4 <= target <= 10^4

进阶:你可以设计一个时间复杂度为 O(log n) 的解决方案吗?

public int search(int[] nums, int target) {
        if (nums.length == 1){
            return target == nums[0] ? 0 : -1;
        }

        int begin = 0;
        int end = nums.length-1;

        while (begin <= end){
            int mid = (begin + end) / 2;
            if (nums[mid]  == target){
                return mid;
            }

            // 0-mid 升序
            if (nums[0] <= nums[mid]){
                if (nums[0] <= target && target < nums[mid]){
                    end = mid-1;
                }else {
                    begin = mid+1;
                }
            }else {

                // mid ~ end 升序  注意等于的情况需要考虑 
                if (nums[mid] < target && target <=nums[nums.length-1]){
                    begin = mid+1;
                }else {
                    end = mid-1;
                }
            }
        }

        return -1;
    }

刷题记录:

  • 2022-03-22 看题解做出

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

原题地址
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:

你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

提示:

0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109

一遍过 代码如下


package xyz.fudongyang.review;

import java.io.Serializable;
import java.lang.annotation.Target;
import java.util.Arrays;

/**
 * @author: fudy
 * @date: 2022/3/23 下午 09:13
 * @Decription:
 **/
public class Lc_34 {
    public static void main(String[] args) {
        int[] nums = {1,2,3,3,3,3,4,5};
        System.out.println(Arrays.toString(searchRange(nums, 3)));
    }

    public static int[] searchRange(int[] nums, int target) {
        if (nums.length == 0) {
            return new int[]{-1, -1};
        }

        int[] ans = new int[]{-1, -1};

        dfs(ans, 0, nums.length - 1, false, target,nums,-1);

        return ans;
    }

    private static void dfs(int[] ans, int begin, int end, boolean isBegin, int target,int [] nums,int beginIndex) {
        if (begin <= end) {
            int mid = (begin + end) / 2;

            if (target == nums[mid]) {
                if (!isBegin) {
                    ans[0] = mid;
                    ans[1] = mid;
                    dfs(ans,begin,mid-1, true,target,nums,mid);
                    dfs(ans,mid+1,end,true,target,nums,mid);
                }else {
                    if (mid > beginIndex){
                        ans[1] = mid;
                        dfs(ans,mid+1,end,true,target,nums,mid);
                    } else if (mid < beginIndex){
                        ans[0] = mid;
                        dfs(ans,begin,mid-1, true,target,nums,mid);
                    }
                }
            }else if (target < nums[mid]){
                dfs(ans,begin,mid-1,isBegin,target,nums,beginIndex);
            }else {
                dfs(ans,mid+1,end,isBegin,target,nums,beginIndex);
            }


        }
    }
}

刷题记录:

  • 2022-03-23 一遍过 太爽了 二分真的恶心

42:接雨水

原题地址
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:
在这里插入图片描述

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6

解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105

java代码

public static int rain(int[] nums) {
        int current = 0;
        int ans = 0;
        Deque<Integer> stack = new LinkedList<>();

        while (current < nums.length) {
            while (!stack.isEmpty() && nums[current] > nums[stack.peek()]) {
                // 弹出上一个小值
                int top = stack.pop();

                // 前面没人承接他
                if (stack.isEmpty()){
                    break;
                }

                // 找到前面承接它的值
                int weight =current - stack.peek() -1;

                // 前面承接它的值 和 后面承接它的值 找一个最小的 ----- 差值
                int height = Math.min(nums[current],nums[stack.peek()]) - nums[top];

                ans += weight * height;

            }
            stack.push(current++);
        }

        return ans;
    }

刷题记录:

  • 2022-03-25 在上班 看题解 刷的

46:全排列

原题地址
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:

输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

示例 2:

输入:nums = [0,1]
输出:[[0,1],[1,0]]

示例 3:

输入:nums = [1]
输出:[[1]]

提示:

1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums 中的所有整数 互不相同

Java代码

    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        List<Integer> data = new ArrayList<>(nums.length);
        boolean[] used = new boolean[nums.length];
        dfs(ans,data,nums,used);

        return ans;
    }

    private static void  dfs(List<List<Integer>> ans,List<Integer> data,int[] nums,boolean[] used){
        if (data.size() == nums.length){
            ans.add(new ArrayList<>(data));
        }

        for (int i = 0; i < nums.length; i++) {
            if (!used[i]){
                data.add(nums[i]);
                used[i] = true;

                dfs(ans,data,nums,used);

                // 这一块没想出来 这是回退的操作
                used[i] = false;
                data.remove(data.size()-1);
            }
        }
    }

刷题记录:

  • 2022-03-25 上班期间刷题 没有一遍过 回退的思想没掌握

48:图像旋转

原题地址
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:

在这里插入图片描述

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

示例 2:

在这里插入图片描述

输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

提示:

n == matrix.length == matrix[i].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000

特别清晰的解题思路
Java代码

    public void rotate(int[][] matrix) {
        // https://leetcode-cn.com/problems/rotate-image/solution/48-xuan-zhuan-tu-xiang-chao-jian-ji-yi-d-nuau/


        // 对角线旋转
        int len = matrix.length;
        for (int i = 0; i < len; i++) {
            for (int j = 0; j < i; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }

        // 再中心对称旋转
        for (int i = 0; i < len; i++) {
            for (int j = 0,k=len-1; j < k; j++,k--) {
                int temp = matrix[i][k];
                matrix[i][k] = matrix[i][j];
                matrix[i][j] = temp;
            }
        }
    }

刷题记录:

  • 2022-03-28 看题解 一刷

200:岛屿数量(今天业务上有这样的需求)

原题地址
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1:

输入:grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
	
输出:1

示例 2:

输入:grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3

提示:

m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] 的值为 '0' 或 '1'
package xyz.fudongyang.le;

/**
 * @author: vfudongyang
 * @createTime: 2022年03月17日 10:36:00
 * @Description:
 */
public class Le_200 {

    private final static char[][] META_DATA = {
            {'1', '1', '0', '0', '0'},
            {'1', '1', '0', '0', '0'},
            {'0', '0', '1', '0', '0'},
            {'0', '0', '0', '1', '1'}
    };

    private final static char[][] META_DATA_2 = {
            {'1', '1', '1'},
            {'0', '1', '0'},
            {'1', '1', '1'}
    };
    private final static char CHECKED = '2';
    private final static char UNCHECK = '1';
    private final static char NOTHING = '0';

    public static void main(String[] args) {
        System.out.println(numIslands(META_DATA));
        System.out.println(numIslands(META_DATA_2));
    }


    public static int numIslands(char[][] grid) {

        int length = grid.length;
        int line = grid[0].length;
        int ans = 0;
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < line; j++) {
                // for 循环每一个元素如果需要遍历 记录位置 作为开端
                if (grid[i][j] == UNCHECK) {
                    System.out.println("i: " + i + " j: " + j);
                    infected(grid, i, j);
                    ans++;
                }
            }
        }

        System.out.println("ans = " + ans);
        return ans;
    }

    private static void infected(char[][] chars, int i, int j) {
        // 遇到1之后 就去感染 感染规则就是 向四周感染 1就置为2 0不变
        if (i - 1 >= 0 && chars[i - 1][j] == UNCHECK) {
            chars[i - 1][j] = CHECKED;
            infected(chars, i - 1, j);
        }
        if (i + 1 < chars.length && chars[i + 1][j] == UNCHECK) {
            chars[i + 1][j] = CHECKED;
            infected(chars, i + 1, j);
        }
        if (j - 1 >= 0 && chars[i][j - 1] == UNCHECK) {
            chars[i][j - 1] = CHECKED;
            infected(chars, i, j - 1);
        }
        if (j + 1 < chars[0].length && chars[i][j + 1] == UNCHECK) {
            chars[i][j + 1] = CHECKED;
            infected(chars, i, j + 1);
        }
    }
}

刷题记录:

  • 2022.03.17 直接一遍过,我记得我看到老师讲的视频这个方法
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值