首页 > 其他分享 >Leetcode刷题记录1 哈希+双指针+滑动窗口

Leetcode刷题记录1 哈希+双指针+滑动窗口

时间:2024-07-07 18:30:18浏览次数:29  
标签:nums int res height 哈希 new left Leetcode 刷题

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

记录一些leetcode刷题中遇到的问题,共勉


hot100

1.哈希

#1.两数之和

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

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

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

方法一:暴力法

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int n = nums.length;
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                if(nums[i]+nums[j]==target){
                    return new int[]{i,j};
                }
            }
        }
        return null;
    }

}

暴力枚举两个数的下标位置

方法二:哈希

class Solution {
    public int[] twoSum(int[] nums, int target) {
        // 元素不重复,使用
        // (key,value):(元素,元素下标)
        Map<Integer,Integer> map = new HashMap<>();
        int n = nums.length;
        for(int i=0;i<n;i++){
            if(map.containsKey(target-nums[i])){
                return new int[]{map.get(target-nums[i]),i};
            }
            map.put(nums[i],i);
        }
        return null;

    }

}

#49.字母异位词分组

题目:给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

方法一:哈希表,先计算每个字符串中对应的字符个数,再将字符个数相等的字符串存入对应list中

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        int len = strs.length;
        int[][] alphabet = new int[len][26];
        // 统计出每个字符串中对应的字符个数
        for(int i=0;i<len;i++){
            String s = strs[i];
            int lenS = s.length();
            for(int j=0;j<lenS;j++){
                alphabet[i][s.charAt(j)-'a']++;
            }
        }

        // 判断是否已经放入list中
        boolean[] used = new boolean[len];

        List<List<String>> res = new ArrayList<>();
        List<String> list;
        // 遍历字符串数组,将所有对应字符相等的字符串,即字母异位词放在同一个list中
        for(int i=0;i<len;i++){
            if(used[i]==false){
                list = new ArrayList<>();
                list.add(strs[i]);
                used[i] = true;
            }
            else{
                continue;
            }      
            for(int j=i+1;j<len;j++){
                if(judgeIsAnagrams(alphabet,i,j)){
                    list.add(strs[j]);
                    used[j] = true;
                }
            }
            res.add(new ArrayList<>(list));
            
        }

        return res;
    }

    public boolean judgeIsAnagrams(int[][] alphabet, int index1, int index2){
        for(int i=0;i<26;i++){
            if(alphabet[index1][i]!=alphabet[index2][i]){
                return false;
            }
        }
        return true;
    }
}

方法二:先按照字母表顺序拼接出各个字母异位词的字符串,再将字符串以及对应存储字符串的列表存入哈希表中

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        int len = strs.length;
        int[][] alphabet = new int[len][26];
        // 统计出每个字符串中对应的字符个数
        for (int i = 0; i < len; i++) {
            String s = strs[i];
            int lenS = s.length();
            for (int j = 0; j < lenS; j++) {
                alphabet[i][s.charAt(j) - 'a']++;
            }
        }

        Map<String, List<String>> map = new HashMap<>();

        for (int i = 0; i < len; i++) {
            // alphabet[i][26]
            StringBuilder sb = new StringBuilder();
            for (int j = 0; j < 26; j++) {
                int temp = alphabet[i][j];
                char c = (char) (j + 'a');
                while (temp-- > 0) {
                    sb.append(c);
                }

            }
            String s = sb.toString();
            // System.out.println("s:"+s+",s.val"+s.hashCode());
            // Java 的字符串常量池机制
            // 如果每次StringBuilder对象中的内容都是相同的,那么在理想情况下它应该只创建一个字符串
            if (map.containsKey(s)) {
                map.get(s).add(strs[i]);
            } else {
                List<String> list = new ArrayList<>();
                list.add(strs[i]);
                map.put(s, list);
            }
        }

        List<List<String>> res = new ArrayList<>();

        for (List<String> value : map.values()) {
            res.add(value);
        }

        return res;

    }
}

#128.最长连续序列

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

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

方法一:排序后进行累加,若不连续,则计数器count归1,重新从下一个数开始累计,这个思路容易想到,二分排序算法时间复杂度O(nlogn)

class Solution {
    public int longestConsecutive(int[] nums) {
        if(nums==null||nums.length==0){
            return 0;
        }
        Arrays.sort(nums);
        int n = nums.length;
        int count=1;
        int res = 1;
        for(int i=0;i<n;i++){
            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }
            
            if(i>0&&nums[i]==nums[i-1]+1){
                count++;
                res = Math.max(res,count);
            }
            else{
                count = 1;
            }
        }

        return res;
    }
}

方法二:借助哈希表来进行判断,快速判断一个数的下一个连续的数是否在数组中出现,跟方法一其实差不多

class Solution {
    public int longestConsecutive(int[] nums) {
        if(nums==null||nums.length==0){
            return 0;
        }
        Arrays.sort(nums);
        Set<Integer> set = new HashSet<>();
        for(int num:nums){
            set.add(num);
        }
        int n = nums.length;
        int count = 1;
        int res = 1;
        for(int i=0;i<n;i++){
            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }
            if(set.contains(nums[i]+1)){
                count++;
                res = Math.max(res,count);
            }
            else{
                count = 1;
            }
        }
        return res;
    }
}

上面两个时间复杂度都没有达到要求,补充一个借鉴的思路
方法三:将数组元素添加进哈希表,之后从一个数开始,若存在与该数有关的连续数组,先找到比它小的最后一个数,从最后一个数开始计数,找到连续的最大长度

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

        int maxLength = 0;

        for (int num : set) {
            if (!set.contains(num - 1)) {
                int currentNum = num;
                int currentLength = 1;

                while (set.contains(currentNum + 1)) {
                    currentNum += 1;
                    currentLength += 1;
                }

                maxLength = Math.max(maxLength, currentLength);
            }
        }

        return maxLength;
    }
}

方法三力扣官方题解时间复杂度分析:link

2.双指针

#283.移动零

题目:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

方法一:暴力法,每次遍历遇到0,则将0交换到数组的末尾位置,同时0的计数器+1,遍历元素的个数-1,将其余元素依次往前移动一位

class Solution {
    public void moveZeroes(int[] nums) {
        int n = nums.length;
        int zeros = 0;
        for (int i = 0; i < n - zeros; i++) {
            if(nums[i]==0){
                for(int j=i;j<n-1-zeros;j++){
                    nums[j] = nums[j+1];
                }
                nums[n-1-zeros] = 0;
                zeros++;
                i--;
            }
        }
    }
}

方法二:双指针法

class Solution {
    public void moveZeroes(int[] nums) {
        int n = nums.length;
        int slow = 0;
        // slow为写指针,fast为读指针
        for (int fast=0;fast<n;fast++) {
            if(nums[fast]!=0){
                nums[slow] = nums[fast];
                slow++;
            }
        }
        //将非零数前移后,一共有slow个非零数,slow指向第一个为0的位置(若存在),往后面的n-slow个数补0
        for(int i=slow;i<n;i++){
            nums[i] = 0;
        }

    }
}

#11.盛最多水的容器

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

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

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

说明:你不能倾斜容器。

方法一:容易想到的思路是暴力枚举两条垂线的位置,不过超时了

class Solution {
    public int maxArea(int[] height) {
        int n = height.length;
        int res = 0;
        int sum = 0;
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                sum = Math.min(height[i],height[j])*(j-i);
                res = Math.max(res,sum);
            }

        }
        return res;
    }
}

方法二:双指针法

class Solution {
    public int maxArea(int[] height) {
        int n = height.length;
        int l = 0,r = n-1;
        int res = 0;
        while(l<=r){
            res = Math.max(res,Math.min(height[l],height[r])*(r-l));
            // 贪心 局部最优->全局最优
            // 当前height[l]<=height[r]时,将左指针向内移动 s = min(height[l],height[r])*(r-l) 
            // 向内移动,(r-l)减小,假设移动l,则min(height[l],height[r])可能增大或减小或不变,s同
            //                     假设移动r,则min(height[l],height[r])减小或不变,s一定减小
            //                     即只有移动l才可能使得s变得更大
            // 向外移动,(r-l)增大,假设移动l,则min(height[l],height[r])减小或增大或不变,s同
            //                     假设移动r,则min(height[l],height[r])减小或不变,s可能不变或增大或减小
            // 由于l与r都由向内移动转移而来,之间处于外圈时res中已经记录最大值,故无需再考虑向外移动的情况
            if(height[l]<=height[r]){
                l++;
            }
            else{
                r--;
            }
        }
        return res;
    }
}

#15.三数之和

题目:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

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

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //  去重之前先排序
        Arrays.sort(nums);

        List<List<Integer>> res = new ArrayList<>();

        int n = nums.length;
        int sum = 0;

        for(int i=0;i<n;i++){
            if(nums[0]>0){
                break;
            }

            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }

            int left = i+1;
            int right = n-1;
            while(left<right){
                sum = nums[i]+nums[left]+nums[right];
                if(sum==0){
                    // 先记录,再去重,否则后面去重完,若出现[0,0,0]这样的情况,三元组凑不够
                    List<Integer> list = new ArrayList<>(Arrays.asList(nums[i],nums[left],nums[right]));
                    res.add(new ArrayList<>(list));
                    while(left<right&&nums[i]+nums[left]+nums[right]==0&&nums[left]==nums[left+1]){
                        left++;
                    }
                    while(left<right&&nums[i]+nums[left]+nums[right]==0&&nums[right]==nums[right-1]){
                        right--;
                    }
                    left++;
                    right--;
                }
                else if(sum>0){
                    right--;
                }
                else{
                    left++;
                }
            }
        }
        return res;


    }
}

需要注意的一个地方是“if(i>0&&nums[i]==nums[i-1]){continue;}”,这个条件表示假设有多个重复的数时候,只取第一个数,算是一种去重的小技巧。

#42.接雨水

题目:给定 n 个非负整数表示每个宽度为 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 个单位的雨水(蓝色部分表示雨水)。

方法一:暴力枚举,按列计算,依次计算每根柱子的位置能接的雨水,步骤为找到该柱子左侧的最大值以及右侧的最大值,取二者中小的一个减去当前柱子高度即得到所能接雨水的值,累加即可


class Solution {
    public int trap(int[] height) {
        int n = height.length;
        int area = 0;
        for(int i=1;i<n-1;i++){
            int leftMaxHeight = height[i];
            for(int j=i-1;j>=0;j--){
                if(leftMaxHeight<height[j]){
                    leftMaxHeight = height[j];
                }
            }
            int rightMaxHeight = height[i];
            for(int j = i+1;j<n;j++){
                if(rightMaxHeight<height[j]){
                    rightMaxHeight = height[j];
                }
            }
            area += Math.min(leftMaxHeight,rightMaxHeight)-height[i];    
        }
        return area;
    }
}

方法二:对方法一做了一些优化,因为判断左侧(右侧)柱子的最大值没必要每次都一直判断到最左侧(最右侧),可以用一个变量来记录当前柱子左侧(右侧)的最大值,之后每次判断当前柱子高度和该柱子左侧(右侧)的变量记录的值即可

class Solution {
    public int trap(int[] height) {
        int n = height.length;
        int area = 0;
        // leftMaxHeight[i]表示height[i]左侧,包括i的height最大值
        // rightMaxHeight[i]表示height[i]右侧,包括i的height最大值
        int[] leftMaxHeight = new int[n];
        int[] rightMaxHeight = new int[n];
        leftMaxHeight[0] = height[0];
        rightMaxHeight[n-1] = height[n-1];
       
        for(int i=1;i<n;i++){
            leftMaxHeight[i] = height[i];
            if(leftMaxHeight[i-1]>height[i]){
                leftMaxHeight[i] = leftMaxHeight[i-1];
            }
        }
        for(int i=n-2;i>=0;i--){
            rightMaxHeight[i] = height[i];
            if(rightMaxHeight[i+1]>height[i]){
                rightMaxHeight[i] = rightMaxHeight[i+1];
            }
        }
        for(int i=1;i<n-1;i++){
            area += Math.min(leftMaxHeight[i],rightMaxHeight[i])-height[i];
        }
        return area;
    }
}

方法三:按行计算,使用单调递增栈,可利用单调递增栈的性质(栈顶到栈底元素单调递增),来找到当前数组中第一个比栈顶元素大的元素。若当前数组的元素比栈元素大,由于栈中元素值单调递增的,之后取出栈顶元素作为中间的基底高度,弹栈之后再次取栈顶元素作为基底左边的高度,当前数组中第一个比栈顶元素大的元素作为基底右边的高度,便可计算当前行能接的雨水,之后再将该元素压入栈中;若当前数组的元素小于或等于栈顶元素,则将其压栈,注意,等于时候可以先弹栈,再压栈,因为此时能接的雨水为0,减少不必要的计算。

class Solution {
    public int trap(int[] height) {
        int n = height.length;
        int area = 0;
        int res=0;
        // 存放索引号
        Stack<Integer> stack  = new Stack<>();
        stack.push(0);
        // 单调递增栈 栈顶到栈底单调递增
        // 按行计算
        for(int i=1;i<n;i++){
            if(height[stack.peek()]>height[i]){
                stack.push(i);
            }
            else if(height[stack.peek()]==height[i]){
                stack.pop();
                stack.push(i);
            }
            else{
                while(!stack.isEmpty()&&height[stack.peek()]<height[i]){
                    int mid = stack.pop();
                    if(!stack.isEmpty()){
                        int left = stack.peek();
                        int w = i-left-1;
                        int h = Math.min(height[left],height[i])-height[mid];
                        area = w*h;
                        res += area;
                    }
                }
                stack.push(i);
            }
        }
        return res;
    }
}

方法四:按列计算,双指针,根据方法一、二可联想到,分别使用两个变量来记录当前元素的左边最大值,以及当前元素的右边最大值,由木桶可知,木桶能接水量的最大值取决于最大的木板,此时不管是左侧最大值大还是右侧最大值大,只要左右两侧都存在比当前元素大的元素,当前位置即能接到雨水,接到雨水的量取决于二者中小的那一个高度,减去当前元素高度

class Solution {
    public int trap(int[] height) {
        // 双指针
        // 按列计算
        int n = height.length;
        int res=0;
        int leftMax = 0;
        int rightMax = n-1;
        int left = 1;
        int right = n-2;
        
        while(left<=right){
            if(height[leftMax]<height[rightMax]){
                if(height[left]<height[leftMax]){
                    res += height[leftMax]-height[left];
                    left++;
                }
                else{
                	// 接不到雨水,left右移,更新leftMax
                    leftMax = left;
                    left++;
                }
            }
            else{
                if(height[right]<height[rightMax]){
                    res += height[rightMax]-height[right];
                    right--;
                }
                else{
                	// 接不到雨水,right左移,更新rightMax
                    rightMax = right;
                    right--;
                }

            }
        }
        return res;
    }
}

3.滑动窗口

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

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

示例 1:

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

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

输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。

方法一:暴力枚举

class Solution {
    public int lengthOfLongestSubstring(String s) {
        char[] chars = s.toCharArray();
        int len = s.length();
        int count = 0;
        int res = 0;
        for(int i=0;i<len;i++){
            Set<Character> set = new HashSet<>();
            for(int j=i;j<len;j++){
                if(set.contains(chars[j])){
                    break;
                }
                set.add(chars[j]);
                count++;
            }
            res = Math.max(res,count);
            count = 0;
        }
        return res;
    }
}

方法二:滑动窗口法,从初始位置开始滑动,当遇到重复字符时候进行回退,回退到具有重复字符的下一个位置,即map.get(chars[i])+1位置处,开始写出的程序为注释掉的left语句,后面遇到测试用例"abba",发现回退时候会回退到第一个字符’b’的位置,从而取得最大值为3,显然与题意不符合,故加以限制条件
left = Math.max(left,map.get(chars[i])+1);
使其不会跳回到之前的状态

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int len = s.length();
        char[] chars = s.toCharArray();
        int res = 0;
        Map<Character,Integer> map = new HashMap<>();
        int left = 0;
        for(int i=0;i<len;i++){
            if(map.containsKey(chars[i])){
                // left = map.get(chars[i])+1;
                left = Math.max(left,map.get(chars[i])+1);
            }
            map.put(chars[i],i);
            res = Math.max(res,i-left+1);
        }
        return res;

    }
}

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

题目:给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

方法一:哈希表+暴力枚举

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        char[] chars = s.toCharArray();
        int lenS = s.length();
        int lenP = p.length();
        List<Integer> res = new ArrayList<>();
        int[] alphabetP = new int[26];
        for(char c:p.toCharArray()){
            alphabetP[c-'a']++;
        }
        for(int i=0;i<lenS;i++){       
            int[] alphabetS = new int[26];
            // 注意限制条件count<lenS,否则数组会越界
            for(int count=i;count<i+lenP&&count<lenS;count++){
                alphabetS[chars[count]-'a']++;
            }
            if(judgeIsCorresponding(alphabetP,alphabetS)){
                res.add(i);
            }      
        }
        return res;
    }

    public boolean judgeIsCorresponding(int[] alphabetP, int[] alphabetS){
        for(int i=0;i<26;i++){
            if(alphabetP[i]!=alphabetS[i]){
                return false;
            }
        }
        return true;
    }
}

方法二:方法一可以进行优化,没必要每次新创建一个哈希表来重新统计修剪之后的字符串s中的各个字符个数,可以采用滑动窗口法,一次滑出上一轮中的第一个元素,并加入这一轮中的新元素

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        char[] chars = s.toCharArray();
        int lenS = s.length();
        int lenP = p.length();
        List<Integer> res = new ArrayList<>();
        int[] alphabetP = new int[26];
        for (char c : p.toCharArray()) {
            alphabetP[c - 'a']++;
        }
        int[] alphabetS = new int[26];
        for (int count = 0; count < lenP && count < lenS; count++) {
            alphabetS[chars[count] - 'a']++;
        }
        if (judgeIsCorresponding(alphabetP, alphabetS)) {
            res.add(0);
        }
        for (int i = lenP; i < lenS; i++) {
            //移除上一轮次的第一个元素
            alphabetS[chars[i-lenP]-'a']--;
            // 添加新元素
            alphabetS[chars[i]-'a']++;
            if (judgeIsCorresponding(alphabetP, alphabetS)) {
                res.add(i-lenP+1);
            }
        }
        return res;

    }

    public boolean judgeIsCorresponding(int[] alphabetP, int[] alphabetS) {
        for (int i = 0; i < 26; i++) {
            if (alphabetP[i] != alphabetS[i]) {
                return false;
            }
        }
        return true;
    }
}

方法三:滑动窗口法,方法参考滑动窗口算法

class Solution {
       public List<Integer> findAnagrams(String s, String p) {
        Map<Character, Integer> window = new HashMap<>();
        Map<Character, Integer> need = new HashMap<>();
        for (char c : p.toCharArray()) {
            need.put(c, need.getOrDefault(c, 0) + 1);
        }
        int left = 0;
        int right = 0;
        int valid = 0;
        List<Integer> result = new ArrayList<>();
        while (right < s.length()) {
            char c = s.charAt(right);
            right++;
            if (need.containsKey(c)) {
                window.put(c, window.getOrDefault(c, 0) + 1);
                if (window.get(c).equals(need.get(c))) {
                    valid++;
                }
            }
            // 判断左侧窗⼝是否要收缩
            while (right - left >= p.length()) {
                // 终止条件
                if (valid == need.size()) {
                    result.add(left);
                }
                char d = s.charAt(left);
                left++;
                //移动left
                if (need.containsKey(d)) {
                    if (window.get(d).equals(need.get(d))) {
                        valid--;
                    }
                    window.put(d, window.get(d) - 1);
                }
            }
        }
        return result;
    }
}

方法四:由方法三改进而来,由于哈希表的长度是固定的,故上面的map可以使用数组来实现同样的效果,少量元素情况下数组空间消耗更小

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        char[] chars = s.toCharArray();
        int len = s.length();
        int[] need = new int[26];
        int[] window = new int[26];
        for(char c:p.toCharArray()){
            need[c-'a']++;
        }
        int count=0;
        for(int num:need){
            if(num!=0){
                count++;
            }
        }
        
        int left = 0;
        int right = 0;
        int valid = 0;
        List<Integer> res = new ArrayList<>();
        while(right<len){
            char c = chars[right];
            right++;
            if(need[c-'a']!=0){
                window[c-'a']++;
                if(window[c-'a']==need[c-'a']){
                    valid++;
                }
            }

            while(right-left>=p.length()){
                if(valid==count){
                    res.add(left);
                }

                char d = chars[left];
                left++;
                if(need[d-'a']!=0){
                    if(need[d-'a']==window[d-'a']){
                        valid--;
                    }
                    window[d-'a']--;
                }
            }
        }
        return res;


    }
}

总结

持续更新中

标签:nums,int,res,height,哈希,new,left,Leetcode,刷题
From: https://blog.csdn.net/destiny3168/article/details/140203454

相关文章

  • [Leetcode]经典算法
    检测环快慢指针法是一种用于检测链表中是否存在环的有效方法,同时也可以找到环的起点。该方法的原理基于两个指针在链表上同时移动,其中一个移动得更快,而另一个移动得更慢。检测环的存在:使用两个指针,一个称为快指针(fast),一个称为慢指针(slow)。在每一步中,快指针向前移动两步,而慢......
  • leetcode678:有效的括号字符串
    给你一个只包含三种字符的字符串,支持的字符类型分别是 '('、')' 和 '*'。请你检验这个字符串是否为有效字符串,如果是 有效 字符串返回 true 。有效 字符串符合如下规则:任何左括号 '(' 必须有相应的右括号 ')'。任何右括号 ')' 必须有相应的左括号 '(' 。左括......
  • 【LeetCode 0024】【链表】交换单链表相邻两个节点
    SwapNodesinPairsGivena linkedlist,swapeverytwoadjacentnodesandreturnitshead.Youmustsolvetheproblemwithout modifyingthevaluesinthelist’snodes(i.e.,onlynodesthemselvesmaybechanged.)Example1:**Input:**head=[1,2,3......
  • 【LeetCode 0141】【链表】【双指针之快慢指针】判断给定单链表是否存在环
    LinkedListCycleGivenhead,theheadofalinkedlist,determineifthelinkedlisthasacycleinit.Thereisacycleinalinkedlistifthereissomenodeinthelistthatcanbereachedagainbycontinuouslyfollowingthe next pointer.Internal......
  • [LeetCode] 1366. Rank Teams by Votes 通过投票对团队排名
    Inaspecialrankingsystem,eachvotergivesarankfromhighesttolowesttoallteamsparticipatinginthecompetition.Theorderingofteamsisdecidedbywhoreceivedthemostposition-onevotes.Iftwoormoreteamstieinthefirstposition,wecon......
  • 代码随想录刷题day 4 | 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题
    24.两两交换链表中的节点迭代的版本:最重要的就是要知道循环变量怎么取,对于这道题,我们只需要存储需要交换的两个节点的前一个节点即可,只有当这个节点后面有两个节点时才进入循环,其实把握住这一点之后这题就非常容易了。递归的版本:这道题用递归做简直不要太简单,首先明白递归结束......
  • leetcode 257. 二叉树的所有路径
    给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。叶子节点 是指没有子节点的节点。 示例1:输入:root=[1,2,3,null,5]输出:["1->2->5","1->3"]示例2:输入:root=[1]输出:["1"]java解题思路及代码实现递归法packagecom.java......
  • leetcode 102. 二叉树的层序遍历
    给你二叉树的根节点 root ,返回其节点值的 层序遍历 。(即逐层地,从左到右访问所有节点)。示例1:输入:root=[3,9,20,null,null,15,7]输出:[[3],[9,20],[15,7]]示例2:输入:root=[1]输出:[[1]]示例3:输入:root=[]输出:[]提示:树中节点数目在范围 [0,2000] ......
  • leetcode77组合——经典回溯算法
    本文主要讲解组合的要点与细节,以及回溯算法的解题步骤,按照步骤思考更方便理解 c++和java代码如下,末尾给定两个整数 n 和 k,返回范围 [1,n] 中所有可能的 k 个数的组合。你可以按 任何顺序 返回答案。 具体要点:1.首先,这道题的暴力解法是k层for循环,遍历所有的......
  • 【LeetCode:3101. 交替子数组计数 + 滑动窗口 + 数学公式】
    ......