牛客Top100热题宝典--第4节

07 字符串

BM83 字符串变形

进阶:空间复杂度 O(n), 时间复杂度 O(n)

// 65   A
// 97   a

String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。

参数2: limit匹配限制
limit的值 含义
大于0 最多匹配limit-1次,次数到了,最后面的作为一个整体返回,数组长度不会超过limit
等于0 一直匹配到结束,但是如果后面全是空串,则丢弃
小于0 一直匹配到结束,不丢弃空串

import java.util.*;
// 65   A
// 97   a
public class Solution {
    public String trans(String s, int n) {
        StringBuilder res = new StringBuilder();
//         注意第二个参数的使用!!
        String[] wordList = s.split(" ",-1);
        int m = wordList.length;
        for (int i = m - 1; i >= 0; i--) {
            System.out.print("***" + wordList[i]);
            char[] tmp = wordList[i].toCharArray();
            for (int j = 0; j < tmp.length; j++) {
                tmp[j] = trans(tmp[j]);
            }
            res.append(new String(tmp));
            res.append(" ");
        }
        return res.substring(0, n).toString();
    }

    public char trans(char ch) {
        if (ch >= 'a' && ch <= 'z') {
            return (char)(ch - ('a' - 'A' ));
        } else
            return (char)(ch + ('a' - 'A'));
    }
}

BM84 最长公共前缀

思路:纵向扫描

进阶:空间复杂度 O(n),时间复杂度 O(n)

import java.util.*;
public class Solution {
    public String longestCommonPrefix (String[] strs) {
        if (strs.length == 0 || strs == null)
            return "";
		//位置不能颠倒!!否则下标溢出!!
        int rows  = strs.length,cols  = strs[0].length();
        for (int j = 0; j < cols ; j++) {
            char prefix = strs[0].charAt(j);
            for (int i = 1; i < rows ; i++) {
                if (strs[i].length() == j || strs[i].charAt(j) != prefix) 
                    return strs[0].substring(0, j);
            }
        }
        return strs[0];
    }
}

BM85 验证IP地址

【力扣!】

BM86 大数加法

import java.util.*;
public class Solution {
    public String solve (String s, String t) {
        StringBuilder res=new StringBuilder();
        int i=s.length()-1,j=t.length()-1;
        int carry=0,bit=0;

        while(i>=0 || j>=0){
            int sum=0;
            // 字符转成整数
            // 方式一  Character.getNumericValue(numChar))
            // 方式二 
            int n1=i>=0?s.charAt(i)-'0':0;
            int n2=j>=0?t.charAt(j)-'0':0;

            sum=n1+n2+carry;
            carry=sum/10;
            bit=sum%10;
            res.append(bit);
            i--;
            j--;
        }
        // 处理1+9样例
        if(carry==1)
        	res.append("1");
        return res.reverse().toString();
    }
}

08 双指针

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

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

方式:滑动窗口

​ 其实就是一个窗口,比如例题中的 abcabcbb,进入这个窗口为 abc 满足题目要求,当再进入 a,窗口变成了 abca,这时候不满足要求。所以,我们要移动这个窗口!

​ 只要把窗口的左边的元素移出就行了,直到满足题目要求!一直维持这样的窗口,找出窗口出现最长的长度时候,求出解!

时间复杂度:O(n)

class Solution {
    public int lengthOfLongestSubstring(String s) {
        HashMap<Character, Integer> map = new HashMap<>();
        int n = s.length();
        int left = -1;
        int right = 0;
        int res = 0;
        while (right < n) {
            char ch = s.charAt(right);
            if (map.containsKey(ch)) {
                left = Math.max(left, map.get(ch));
            }
            map.put(ch, right);
            res = Math.max(res, right - left);
            right++;
        }
        return res;
    }
}

BM87 合并两个有序的数组

import java.util.*;
public class Solution {
    public void merge(int A[], int m, int B[], int n) {
        int[] res = new int[m + n];
        int i=0,j=0,p=0;
        while(i<m && j<n){
            res[p++]=A[i]<=B[j]?A[i++]:B[j++];
        }
        while(i<m){
            res[p++]=A[i++];
        }
        while(j<n){
            res[p++]=B[j++];
        }

        for(int r=0;r<p;r++){
            A[r]=res[r];
        }
    }
}

BM88 判断是否为回文字符串

import java.util.*;

// 2,使用StringBuffer
public class Solution {

    public boolean judge (String str) {
        String rev=new StringBuilder(str).reverse().toString();
        return str.equals(rev);
    }
}

BM89 合并区间

思路:
先按照区间起始位置排序,如果intervals[i][1]>=intervals[i+1][0],那么循环合并两个区间。
import java.util.*;
// 难点:分析intervals结构,根据结构进行解题!!
public class Solution {
    public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
        ArrayList<Interval> res = new ArrayList<>();
        Collections.sort(intervals, (a, b)->a.start - b.start);
        int len=intervals.size();
        int i=0;
        while(i<len){
            int left=intervals.get(i).start;
            int right=intervals.get(i).end;

            while(i+1<len && right>=intervals.get(i+1).start){
                right=Math.max(right,intervals.get(i+1).end);
                i++;
            }
            res.add(new Interval(left,right));
            i++;
        }
        return res;
    }
}


class Solution {
    public static int[][] merge(int[][] intervals) {
        int n = intervals.length;
        List<int[]> res = new ArrayList<>();
        Arrays.sort(intervals, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0] - o2[0];
            }
        });
        int i = 0;
        while (i < n) {
            int left = intervals[i][0];
            int right = intervals[i][1];
            while (i+1<n && intervals[i + 1][0] <= right) {
                right = Math.max(right, intervals[i + 1][1]);
                i++;
            }
            res.add(new int[]{left, right});
            i++;
        }
        //二维list转换成二维数组
        return res.toArray(new int[res.size()][]);
    }
}

BM90 最小覆盖子串 【难!!!】

要求: 时间复杂度 O(n)

思路:滑动窗口

【包含小写字母和大写字母!!】

当窗口内的所有字符不能覆盖t的时候,要扩大窗口,也就是right往右移。
当窗口内的所有字符可以覆盖t的时候,记录窗口的起始位置以及窗口的长度,然后缩小窗口(因为这里求的是能覆盖的最小子串),left往右移。如果缩小的窗口还能覆盖t,保存长度最小的窗口即可。
重复上面的操作,直到窗口的右边不能再移动为止。

import java.util.*;
public class Solution {
    public String minWindow (String S, String T) {
        int m = S.length(), n = T.length();
        //map确保窗口是否覆盖全部T中的字符
        HashMap<Character, Integer> map = new HashMap<>();
        //把T中的字符全部放到map中
        for (char ch : T.toCharArray())
            map.put(ch, map.getOrDefault(ch, 0) + 1);

        //窗口的左边界和右边界
        int left = 0, right = 0;

        //窗口开始位置
        int start = 0;
        //窗口的长度
        int winLength = Integer.MAX_VALUE;

        while (right < m) {
            char rightChar = S.charAt(right);
            // 如果右指针扫描的字符存在于map中,就减1
            if (map.containsKey(rightChar)) {
                map.put(rightChar, map.get(rightChar) - 1);
            }
            right++;
            // 检查窗口是否把t中字符全部覆盖了,如果覆盖了,要移动窗口的左边界
            while (check(map)) {
                // 如果现在窗口比之前保存的还要小,就更新窗口的长度
                // 以及窗口的起始位置
                if (right - left < winLength) {
                    winLength = right - left;
                    start = left;
                }
                // 移除窗口最左边的元素,也就是缩小窗口
                char leftChar = S.charAt(left);
                if (map.containsKey(leftChar)) {
                    // 表示窗口中欠缺该字符,没有包含该字符!!
                    map.put(leftChar, map.get(leftChar) + 1);
                }
                left++;
            }
        }
        return winLength != Integer.MAX_VALUE ? S.substring(start,
                start + winLength) : "";
    }
    // 检查窗口是否把字符串t中的所有字符都覆盖了,如果map中所有
    // value的值都不大于0,则表示全部覆盖
    public boolean check(HashMap<Character, Integer> map) {
        for (int value : map.values()) {
            if (value > 0) return false;
        }
        return true;
    }
}

getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值。

getOrDefault() 方法的语法为:

hashmap.getOrDefault(Object key, V defaultValue)

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

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

方式一:滑动窗口(左右指针)

【仅包含小写字母!!】

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> res = new ArrayList<>();
        int[] chs = new int[26];
        int[] chp = new int[26];
        int n = s.length();
        int m = p.length();
        for (int i = 0; i < p.length(); i++) {
            chp[p.charAt(i) - 'a']++;
        }
        for (int left = 0, right = 0; right < n; right++) {
            char rightChar = s.charAt(right);
            chs[rightChar - 'a']++;

            if (right - left + 1 > m) {
                char leftChar = s.charAt(left);
                chs[leftChar - 'a']--;
                left++;
            }
            if (check(chs, chp)) res.add(left);
        }
        return res;
    }

    private boolean check(int[] chs, int[] chp) {
        for (int i = 0; i < 26; i++) {
            if (chs[i] != chp[i])
                return false;
        }
        return true;
    }
}

BM92 最长无重复子数组

【可能有多个无重复数组,选择长度最长的一个数组!!】

使用集合set来代替队列,用两个指针,一个left一个right,如果有重复的就把left指向的给移除(left相当于队首,right相当于队尾)

import java.util.*;
public class Solution {
    public int maxLength (int[] arr) {
        int res = 0;
        HashSet<Integer> set = new HashSet<>();
        int left = 0, right = 0;
        int n = arr.length;
        while (right < n) {
            if (!set.contains(arr[right])) {
                set.add(arr[right++]);
                res = Math.max(res, set.size());
            } else {
                set.remove(arr[left++]);
            }
        }
        return res;
    }
}

BM93 盛水最多的容器

双指针
在这里插入图片描述
在这里插入图片描述

public class Solution {
    public int maxArea (int[] height) {
        int n = height.length;
        int left = 0;
        int right = n - 1;
        int res = 0;
        //此处不能相等,因为面积不能为0
        while (left < right) {
            if (height[left] < height[right]) {
                res = Math.max(res, (right - left) * height[left]);
                left++;
            } else  {
                res = Math.max(res, (right - left) * height[right]);
                right--;
            }
        }
        return res;
    }
}

BM94 接雨水问题

import java.util.*;
public class Solution {

    public long maxWater (int[] arr) {
        int n = arr.length;
        long res = 0;
        int[] lMax = new int[n];
        int[] rMax = new int[n];
        lMax[0]=arr[0];
        rMax[n-1]=arr[n-1];
        for (int i = 1; i < n; i++) {
            lMax[i] = Math.max(arr[i], lMax[i - 1]);
        }

        for (int i = n - 2; i >=0; i--) {
            rMax[i] = Math.max(arr[i], rMax[i+1]);
        }

        for (int i = 0; i < n; i++) {
            res+=Math.min(lMax[i], rMax[i]) - arr[i];
        }
        return res;
    }
}

283. 移动零

283. 移动零

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

方式:双指针

left指向0的下一个位置,right用于遍历数组,交换数字即可

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

    private void swap(int[] nums, int left, int right) {
        int tmp = nums[left];
        nums[left] = nums[right];
        nums[right] = tmp;
    }
}

581. 最短无序连续子数组

581. 最短无序连续子数组
​ 一般来说题目如果暗示你可以O(n)对序列进行操作的话,就可以考虑一下双指针的解法。这道题的双指针其实不是很明显,需要一定的思考。

https://leetcode.cn/problems/shortest-unsorted-continuous-subarray/solution/581-zui-duan-wu-xu-lian-xu-zi-shu-zu-si-8rivt/

​ 思路:数组分成三段,第一段中最大元素小于中间段的最小元素,中间段最大元素小于第三段最小元素,且首段和尾段的元素是有序的。找到对应的边界即可。

  • 从左往右遍历,边遍历边确定遍历区间的最大值,如果当前值小于最大值,那么这个值肯定需要排序,这样就可以确定右边界
  • 从右往左遍历,边遍历边确定遍历区间的最小值,如果当前值大于最小值,那么这个值肯定需要排序,这样就可以确定左边界
  • 可以使用一次遍历直接进行从左往右和从右往左遍历。
class Solution {
    public int findUnsortedSubarray(int[] nums) {
        int n = nums.length;
        // 最后一个逆序的位置!!
        int left = -1;
        int right = -1;
        int maxn = Integer.MIN_VALUE;
        int minn = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            if (nums[i] >= maxn) {
                maxn = nums[i];
            } else {
                right = i;
            }

            if (nums[n - 1 - i] <= minn)
                minn = nums[n - 1 - i];
            else
                left = n - 1 - i;
        }
        return right == -1 ? 0 : right - left + 1;
    }
}

整理不易🚀🚀,关注和收藏后拿走📌📌欢迎留言🧐👋📣
欢迎专注我的公众号AdaCoding 和 Github:AdaCoding123
在这里插入图片描述

  • 33
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值