LeetCode刷题记录(数组和双指针)

文章目录

数组专题

88. 合并两个有序数组

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m-1;
        int j = n-1;
        int k = m+n-1;
        while(i>=0 && j>=0){
            if(nums1[i]>nums2[j]){
                nums1[k--] = nums1[i--];
            }else{
                nums1[k--] = nums2[j--];
            }
        }
        while (j>=0){
            nums1[k--] = nums2[j--];
        }
    }
}

90. 子集 II

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        if(nums.length==0 || nums==null) return res;
        Arrays.sort(nums);
        boolean[] used = new boolean[nums.length];
        dfs(nums,new ArrayList<Integer>(),0,used);
        return res;
    }

    private void dfs(int[] nums, ArrayList<Integer> path, int start, boolean[] used) {
        res.add(new ArrayList<>(path));
        for (int i=start;i<nums.length;i++){
            if(used[i]==true) continue;
            if(i>0 && nums[i]==nums[i-1] && used[i-1]==false) continue;
            path.add(nums[i]);
            used[i] = true;
            
            dfs(nums,path,i+1,used);
            
            path.remove(path.size()-1);
            used[i] = false;
        }
    }
}

105. 从前序与中序遍历序列构造二叉树

class Solution {
    HashMap<Integer,Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        int preleft = 0;
        int preright = preorder.length-1;
        int inleft = 0;
        int inright = inorder.length-1;
        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i],i);
        }
        return dfs(preleft,preright,inleft,inright,preorder,inorder);
    }

    private TreeNode dfs(int preleft, int preright, int inleft, int inright, int[] preorder, int[] inorder) {
        if(inleft>inright || preleft>preright) return null;
        int rootValue = preorder[preleft];
        TreeNode root = new TreeNode(rootValue);

        int index = map.get(rootValue);
        
        root.left = dfs(preleft+1,preleft+index-inleft,inleft,index-1,preorder,inorder);
        root.right = dfs(preleft+index-inleft+1,preright,index+1,inright,preorder,inorder);
        return root;
    }
}

106. 从中序与后序遍历序列构造二叉树

class Solution {
    HashMap<Integer,Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        int inleft = 0;
        int inright = inorder.length-1;
        int postleft = 0;
        int postright = postorder.length-1;

        for(int i=0;i<inorder.length;i++){
            map.put(inorder[i],i);
        }

        return dfs(inleft,inright,postleft,postright,inorder,postorder);
    }

    private TreeNode dfs(int inleft, int inright, int postleft, int postright, int[] inorder, int[] postorder) {
        if(inleft>inright || postleft>postright) return null;
        int rootValue = postorder[postright];
        TreeNode root = new TreeNode(rootValue);

        int index = map.get(rootValue);

        root.left = dfs(inleft,index-1,postleft,postleft+index-inleft-1,inorder,postorder);
        root.right = dfs(index+1,inright,postleft+index-inleft,postleft+inright-inleft-1,inorder,postorder);
        return root;
    }
}

118. 杨辉三角 (no)

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> generate(int numRows) {
        for(int i=0;i<numRows;i++){
            List<Integer> list = new ArrayList<>();
            for(int j=0;j<=i;j++){
                if(j==0 || j==i){
                    list.add(1);
                } else{
                  list.add(res.get(i-1).get(j-1)+res.get(i-1).get(j));  
                }
            }
            res.add(list);
        }
        return res;
    }
}

119. 杨辉三角 II

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    //rowIndex是从0开始的
    public List<Integer> getRow(int rowIndex) {
        for(int i=0;i<=rowIndex;i++){
            List<Integer> list = new ArrayList<>();
            for(int j=0;j<=i;j++){
                if(j==0 || j==i){
                    list.add(1);
                } else {
                    list.add(res.get(i-1).get(j-1)+res.get(i-1).get(j));
                }
            }
            res.add(list);
        }
        return res.get(rowIndex);
    }
}

120. 三角形最小路径和 (no)

class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();
        int[][] dp = new int[n][n];
        dp[0][0] = triangle.get(0).get(0);
        for(int i=1;i<n;i++){
            dp[i][0] = dp[i-1][0]+triangle.get(i).get(0);
            for(int j=1;j<i;j++){
                dp[i][j] = Math.min(dp[i-1][j-1],dp[i-1][j])+triangle.get(i).get(j);
            }
            dp[i][i] = dp[i-1][i-1]+triangle.get(i).get(i);
        }
        //最小路径和一定在下面的最后一行
        int minTol = dp[n-1][0];
        for(int i=1;i<n;i++){
             minTol = Math.min(dp[n-1][i],minTol);
        }
        return minTol;
    }
}

121. 买卖股票的最佳时机

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length==0) return 0;
        //注意:j的取值只有两个状态
        int[][] dp = new int[prices.length][2];
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        for(int i=1;i<prices.length;i++){
            dp[i][0] = Math.max(dp[i-1][0],-prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
        }
        return dp[prices.length-1][1];
    }
}

122. 买卖股票的最佳时机 II

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length==0) return 0;
        int[][] dp = new int[prices.length][2];
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        for(int i=1;i<prices.length;i++){
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]-prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
        }
        return dp[prices.length-1][1];
    }
}

123. 买卖股票的最佳时机 III

class Solution {
    public int maxProfit(int[] prices) {
        if(prices.length==0) return 0;
        int[][] dp = new int[prices.length][4];
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[0][2] = -prices[0];
        dp[0][3] = 0;
        
        for(int i=1;i<prices.length;i++){
            dp[i][0] = Math.max(dp[i-1][0],-prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
            dp[i][2] = Math.max(dp[i-1][2],dp[i-1][1]-prices[i]);
            dp[i][3] = Math.max(dp[i-1][3],dp[i-1][2]+prices[i]);
        }
        return Math.max(dp[prices.length-1][1],dp[prices.length-1][3]);
    }
}

152. 乘积最大子数组(no)

暴力法:

class Solution {
    public static int maxProduct(int[] nums) {
        int res = nums[0];
        for(int i=0;i<nums.length;i++){
            int multi = 1;
            for(int j=i;j<nums.length;j++){
                multi *= nums[j];
                res = Math.max( multi,res);
            }
        }
        return res;
    }
}

动态规划解法:

class Solution {
    public static int maxProduct(int[] nums) {
        //因为当前数有正数也有负数,因此维持一个最大的乘积子数组和最小的乘积子数组
        int[] maxdp = new int[nums.length];
        int[] mindp = new int[nums.length];
        maxdp[0] = nums[0];
        mindp[0] = nums[0];
        int res = nums[0];
        for(int i=1;i<nums.length;i++){
            //最大的乘积子数组(如果当前数是个负数,上个状态是正数那就是mindp[i-1]*nums[i])
            maxdp[i] = Math.max(Math.max(maxdp[i-1]*nums[i],mindp[i-1]*nums[i]),nums[i]);
            //最小的乘积子数组(如果当前是个负数,上个状态是正数,那就是maxdp[i-1]*nums[i])
            mindp[i] = Math.min(Math.min(maxdp[i-1]*nums[i],mindp[i-1]*nums[i]),nums[i]);
            res = Math.max(maxdp[i],res);
        }
        return res;
    }
}

153. 寻找旋转排序数组中的最小值

class Solution {
    public int findMin(int[] nums) {
        if(nums.length==0) return 0;
        int start = 0;
        int end = nums.length-1;
        while (start+1<end){
            int mid = start+(end-start)/2;
            if(nums[mid]>nums[end]){
                start = mid;
            }else if(nums[mid]<nums[end]){
                end = mid;
            }else if(nums[mid]==nums[end]){
                end--;
            }
        }
        if(nums[start]<nums[end]){
            return nums[start];
        }else{
            return nums[end];
        }
    }
}

169. 多数元素

class Solution {
    public int majorityElement(int[] nums) {
        if(nums.length==0) return 0;
        int mainNum = 0;
        int count = 0;
        for(int i=0;i<nums.length;i++){
            if(count==0){
                mainNum = nums[i];
            }
            if(nums[i]==mainNum){
                count++;
            }else{
                count--;
            }
        }
        return mainNum;
    }
}

189. 旋转数组

class Solution {
    public void rotate(int[] nums, int k) {
        if(nums.length==0) return;
        k = k % (nums.length);
        //先对所有的数进行反转
        reverse(nums,0,nums.length-1);
        //再反转0-k之间的数
        reverse(nums,0,k-1);
        //反转k-n之间的数
        reverse(nums,k,nums.length-1);
    }

    private void reverse(int[] nums,int i,int j) {
        while (i<j){
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
            i++;
            j--;
        }
    }
}

209. 长度最小的子数组

暴力法:

class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        if(nums.length==0) return 0;
        int minLen = Integer.MAX_VALUE;
        for(int i=0;i<nums.length;i++){
            int sum = 0;
            for(int j=i;j<nums.length;j++){
                sum = sum + nums[j];
                if(sum>=s){
                    minLen = Math.min(minLen,j-i+1);
                }
            }
        }
        return minLen==Integer.MAX_VALUE ? 0:minLen;
    }
}

216. 组合总和 III

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> combinationSum3(int k, int n) {
        int arr[] = new int[]{1,2,3,4,5,6,7,8,9};
        dfs(arr,k,n,new ArrayList<Integer>(),0);
        return res;
    }

    private void dfs(int[] arr, int k, int n, ArrayList<Integer> path, int start) {
        if(path.size()==k && n==0){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int i=start;i<arr.length;i++){
            path.add(arr[i]);
            n = n-arr[i];

            dfs(arr,k,n,path,i+1);

            path.remove(path.size()-1);
            n = n +arr[i];
        }
    }
}

0. 有赞笔试

题目:求s=a+aa+aaa+aaaa+aa…a的值,其中a是一个数字。例如2+22+222+2222+22222(此时共有5个数相加)

class Solution {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String[] split = scanner.next().split(",");
        int num = Integer.parseInt(split[0]);
        int n = Integer.parseInt(split[1]);
        int res = 0;
        int sum = 0;
        while (n>0){
            res = res*10+num;
            sum += res;
            n--;
        }
        System.out.println(sum);
    }
}

217. 存在重复元素

哈希表算法:

class Solution {
    public boolean containsDuplicate(int[] nums) {
        if(nums.length==0) return false;
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<nums.length;i++){
            map.put(nums[i],map.getOrDefault(nums[i], 0)+1);
        }
        Set<Integer> keySet = map.keySet();
        for(Integer key:keySet){
            if(map.get(key)>=2){
                return true;
            }
        }
        return false;
    }
}

暴力算法:

class Solution {
    public boolean containsDuplicate(int[] nums) {
        if(nums.length==0) return false;
        for(int i=0;i<nums.length-1;i++){
            for(int j=i+1;j<nums.length;j++){
                if(nums[j]==nums[i]){
                    return true;
                }
            }
        }
        return false;
    }
}

考虑排序算法:

class Solution {
    public boolean containsDuplicate(int[] nums) {
        if(nums.length==0) return false;
        Arrays.sort(nums);
        for(int i=0;i<nums.length-1;i++){
            if(nums[i]==nums[i+1]){
                return true;
            }
        }
        return false;
    }
}

238. 除自身以外数组的乘积

暴力解法:超时

class Solution {
    public int[] productExceptSelf(int[] nums) {
        if(nums.length==0) return new int[0];
        int [] arr = new int[nums.length];
        for(int i=0;i<nums.length;i++){
            int multi = 1;
            for(int j=0;j<nums.length;j++){
                if(j!=i){
                    multi = multi*nums[j];
                    arr[i] = multi;
                }
            }
        }
        return arr;
    }
}

前缀和的概念:额外创建一个数组 sums 用于存储数组 nums 的前缀和,其中 sums[i] 表示从 nums[0] 到 nums[i−1] 的元素和。

sums[0] = 0;
for (int i = 1; i <= n; i++) {
	sums[i] = sums[i - 1] + nums[i - 1];
}

优化空间复杂度:给定索引 i,我们将使用它左边所有数字的乘积乘以右边所有数字的乘积。

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n = nums.length;
        //给定索引 i,我们将使用它左边所有数字的乘积乘以右边所有数字的乘积。
        int[] pre = new int[n];
        int[] post = new int[n];

        //pre[i] 为索引 i 左侧所有元素的乘积
        pre[0] = 1;
        for(int i=1;i<nums.length;i++){
            pre[i] = pre[i-1] * nums[i-1];
        }

        //post[i] 为索引 i 右侧所有元素的乘积
        post[n-1] = 1;
        for(int i=n-2;i>=0;i--){
            post[i] = post[i+1]*nums[i+1];
        }

        int[] res = new int[n];
        for (int i = 0; i < n; i++) {
            res[i] = pre[i] * post[i];
        }
        return res;
    }
}

268. 缺失数字(no)

class Solution {
    public int missingNumber(int[] nums) {
        if(nums.length==0 || nums==null) return 0;
        Arrays.sort(nums);
        int m = 0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=m){
                break;
            }
            m++;
        }
        return m;
    }
}

利用等差数列的公式,求出0-n的总和,然后减去数组中的数,最后的结果就是缺失的数字

class Solution {
    public int missingNumber(int[] nums) {
        int n = nums.length;
        int sum = (n+1)*n/2;
        for(int i=0;i<nums.length;i++){
            sum = sum-nums[i];
        }
        return sum;
    }
}

283. 移动零

class Solution {
    public void moveZeroes(int[] nums) {
        if(nums.length==0 || nums==null) return;
        int i=0;
        for(int j=0;j<nums.length;j++){
            if(nums[j]!=0){
                nums[i] = nums[j];
                i++;
            }
        }
        for(int k = i;k<nums.length;k++){
            nums[k] = 0;
        }
    }
}

414. 第三大的数 (no)

本题的关键在于能不能想到去重,拿到题目思考的角度:去重有没有影响,可以可以考虑?排序有没有影响,可不可以考虑?

class Solution {
    public int thirdMax(int[] nums) {
        Arrays.sort(nums);
        //list插入是有序的
        ArrayList<Integer> list = new ArrayList<>();
        for(int i=0;i<nums.length;i++){
            if(!list.contains(nums[i])){
                list.add(nums[i]);
            }
        }
        if(list.size()<3){
            return list.get(list.size()-1);
        }else {
            return list.get(list.size()-3);
        }
    }
}

使用Treeset集合来维护三个最大的数:

class Solution {
    public int thirdMax(int[] nums) {
        //set不想list那样可以根据索引取值,但是给数组排序后,可以通过手动去重的方式达到TreeSet的效果,而且更好用
        TreeSet<Integer> set = new TreeSet<>();
        for(int i=0;i<nums.length;i++){
            set.add(nums[i]);
            //使用Treeset维护一个只有三个元素的set集合,当元素个数大于3时,把第一个元素移除
            if(set.size()>3){
                set.remove(set.first());
            }
        }
        if(set.size()<3){
            return set.last();
        }else{
            return set.first();
        }
    }
}

442. 数组中重复的数据

先排序,然后判断是否重复:

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> findDuplicates(int[] nums) {
        Arrays.sort(nums);
        for(int i=1;i<nums.length;i++){
            if(nums[i]==nums[i-1]){
                res.add(nums[i]);
            }
        }
        return res;
    }
}

使用哈希表统计次数:

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> findDuplicates(int[] nums) {
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<nums.length;i++){
            map.put(nums[i],map.getOrDefault(nums[i],0)+1);
        }
        Set<Integer> keySet = map.keySet();
        for(Integer key:keySet){
            if(map.get(key)==2){
                res.add(key);
            }
        }
        return res;
    }
}

利用数组中的元素范围在1-n之内,可以得出数组中的元素和数组下标 有对应的关系

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> findDuplicates(int[] nums) {
        for(int i=0;i<nums.length;i++){
            int index = Math.abs(nums[i])-1;
            if(nums[index]>0){
                nums[index] = nums[index]*(-1);
            }else{
                res.add(index+1);
            }
        }
        return res;
    }
}

448. 找到所有数组中消失的数字

方法一:先试用hash表记录一遍所有出现的数,然后遍历1-n范围内的数查找不在哈希表中的数

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> findDisappearedNumbers(int[] nums) {
        HashSet<Integer> set = new HashSet<Integer>();
        //先将数组中出现的数放入set集合中(list集合和HashMap也可以)
        for(int i=0;i<nums.length;i++){
            set.add(nums[i]);
        }

        //数的范围是1-n:判断1-n范围内的数哪个没有在set集合中,如果没在即加入res
        for(int i=1;i<=nums.length;i++){
            if(!set.contains(i)){
                res.add(i);
            }
        }
        return res;
    }
}

方法二:数组和元素的下标存在关系:

class Solution {
    List<Integer> res = new ArrayList<>();
    public List<Integer> findDisappearedNumbers(int[] nums) {
        //1-n之间的数 正好对应 0到n-1之间的数组下标
        /**
         *  1   2   3   4   5
         *  0   1   2   3   4
         *
         *  如果一个数在数组中出现过,我们将让这个数-1对应的数组下标上的元素变为负数
         *  如果以这个数为下标的数,在数组中对应的元素为负数,说明这个数加1出现过,如果为正数,说明这个数加1没出现过
         */
        for(int i=0;i<nums.length;i++){
            //将以这个数减1位索引下标的数置为负数
            int index = Math.abs(nums[i])-1;
            if(nums[index]>0){
                nums[index] = nums[index]*(-1);
            }
        }

        for(int i=1;i<=nums.length;i++){
            if(nums[i-1]>0){
                res.add(i);
            }
        }
        return res;
    }
}

41. 缺失的第一个正数

暴力算法:先将每个数放入hash表中,如果[1-num.length]之间的数字没有出现在set中说明是缺失的,如果都出现在了,那么需要返回num.length+1

class Solution {
    public int firstMissingPositive(int[] nums) {
        if(nums.length==0) return 0;
        HashSet<Integer> set = new HashSet<>();
        for(int i=0;i<nums.length;i++){
            set.add(nums[i]);
        }

        for(int i=1;i<=nums.length;i++){
            if(!set.contains(i)){
                return i;
            }
        }
        return nums.length+1;
    }
}

如果不开辟额外的空间:

class Solution {
    public int firstMissingPositive(int[] nums) {
        if(nums.length==0) return 1;

        //将所有小于等于0的数标记为n+1
        for(int i=0;i<nums.length;i++){
            if(nums[i]<=0){
                nums[i] = nums.length+1;
            }
        }

        for(int i=0;i<nums.length;i++){
            int index = Math.abs(nums[i])-1;
            if(index<nums.length){
                nums[index] = -Math.abs(nums[index]) ;
            }
        }

        for(int i=0;i<nums.length;i++){
            if(nums[i]>0){
                return i+1;
            }
        }
        return nums.length+1;
    }
}

485. 最大连续1的个数

暴力算法:

class Solution {
    public int findMaxConsecutiveOnes(int[] nums) {
        int count = 0;
        int res = 0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]==1){
                count++;
                res = Math.max(res,count);
            }else{
                count = 0;
            }
        }
        return res;
    }
}

对上述代码的改进:

class Solution {
    public int findMaxConsecutiveOnes(int[] nums) {
        int count = 0;
        int res = 0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]==1){
                count++;
            }else{
                res = Math.max(res,count);
                count = 0;
            }
        }
        return Math.max(res,count);
    }
}

560. 和为K的子数组

暴力法:

class Solution {
    public int subarraySum(int[] nums, int k) {
        int count = 0;
        for(int i=0;i<nums.length;i++){
            int sum = 0;
            for(int j=i;j<nums.length;j++){
                sum += nums[j];
                if(sum==k){
                    count++;
                }
            }
        }
        return count;
    }
}

0. 滴滴笔试题

给你一个字符串,每次截取n个进行逆序,然后拼接在一起,比如:gogogoout

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String m = sc.nextLine();
        String s = sc.nextLine();

        int n = Integer.parseInt(m);
        String res = "";

        int len = s.length();
        int i = 0;

        while (i + n < len){
            StringBuilder sb = new StringBuilder(s.substring(i, i + n));
            sb = sb.reverse();
            res += sb.toString();
            i += n;
        }

        StringBuilder sb = new StringBuilder(s.substring(i, len));
        sb = sb.reverse();
        res += sb.toString();
        System.out.println(res);
    }
}

双指针专题

925. 长按键入

class Solution {
    public boolean isLongPressedName(String name, String typed) {
        int i=0;
        int j = 0;
        while (i<name.length() || j<typed.length()){
            //如果两个指针指向的字符相等,就让两个指针向后移动
            if(i<name.length() && j<typed.length() && name.charAt(i)==typed.charAt(j)){
                i++;
                j++;
            //如果不相等,有两种情况,一种是j指向的字符和前面的相等,一种是false
            }else{
                if(j>0 && j<typed.length() && typed.charAt(j)==typed.charAt(j-1)){
                    j++;
                }else{
                    return false;
                }
            }
        }
        return true;
    }
}

125. 验证回文串

class Solution {
    public boolean isPalindrome(String s) {
        //题目说只考虑字母和数字字符
        if(s.length()==0) return true;
        int i=0;
        int j = s.length()-1;
        while (i<j){
            //如果不是字母和数字,直接跳过
            while (i<j && !Character.isLetterOrDigit(s.charAt(i))) i++;
            while (i<j && !Character.isLetterOrDigit(s.charAt(j))) j--;
            if(Character.toLowerCase(s.charAt(i))!=Character.toLowerCase(s.charAt(j))){
                return false;
            }else{
                i++;
                j--;
            }
        }
        return true;
    }
}

88. 合并两个有序数组

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m-1;
        int j = n-1;
        int k = m+n-1;
        while (i>=0 && j>=0){
            if(nums1[i]<nums2[j]){
                nums1[k--] = nums2[j--];
            }else{
                nums1[k--] = nums1[i--];
            }
        }
        while (j>=0){
            nums1[k--] = nums2[j--];
        }
    }
}

27. 移除元素

class Solution {
    public int removeElement(int[] nums, int val) {
        if(nums.length==0 || nums==null) return 0;
        int i=0;
        for(int j=0;j<nums.length;j++){
            if(nums[j]!=val){
                nums[i] = nums[j];
                i++;
            }
        }
        return i;
    }
}

283. 移动零

class Solution {
    public void moveZeroes(int[] nums) {
        if(nums.length==0 || nums==null) return;
        for(int i=1;i<nums.length;i++){
            int insertValue = nums[i];
            int insertIndex = i;
            while (insertIndex>0 && nums[insertIndex-1]==0){
                nums[insertIndex] = nums[insertIndex-1];
                insertIndex--;
            }
            nums[insertIndex] = insertValue;
        }
    }
}

方法二:和上一题的思路完全相同,使用双指针

class Solution {
    public void moveZeroes(int[] nums) {
        //思路就是把非0元素都放到前面,剩余的元素都置0
        int i=0;
        for(int j=0;j<nums.length;j++){
            if(nums[j]!=0){
                nums[i] = nums[j];
                i++;
            }
        }
        for(int k = i;k<nums.length;k++){
            nums[k] = 0;
        }
    }
}

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

class Solution {
    public int removeDuplicates(int[] nums) {
        if(nums.length==0 || nums==null) return 0;
        int i=0;
        for(int j=0;j<nums.length;j++){
            if(nums[j]!=nums[i]){
                i++;
                nums[i] = nums[j];
            }
        }
        return i+1;
    }
}

344. 反转字符串

class Solution {
    public void reverseString(char[] s) {
        int i=0;
        int j = s.length-1;
        while (i<j){
            char temp = s[i];
            s[i] = s[j];
            s[j] = temp;
            i++;
            j--;
        }
    }
}

167. 两数之和 II - 输入有序数组

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int i=0;
        int j = numbers.length-1;
        while (i<j){
            if(numbers[i]+numbers[j]>target){
                j--;
            }else if(numbers[i]+numbers[j]<target){
                i++;
            }else{
                return new int[]{i+1,j+1};
            }
        }
        return new int[]{-1,-1};
    }
}

350. 两个数组的交集 II

方法一:双指针

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        int i=0;
        int j = 0;
        ArrayList<Integer> list = new ArrayList<>();
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        while (i<nums1.length && j<nums2.length){
            if(nums1[i]<nums2[j]) {
                i++;
            } else if(nums1[i]>nums2[j]){
                j++;
            }else{
                list.add(nums1[i]);
                i++;
                j++;
            }
        }
        int[] arr = new int[list.size()];
        int index = 0;
        for(int k=0;k<arr.length;k++){
            arr[index++] = list.get(k);
        }
        return arr;
    }
}

另一种写法:可以学习一下

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        int i=0;
        int j = 0;
        int index = 0;
        int[] arr = new int[Math.min(nums1.length,nums2.length)];
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        while (i<nums1.length && j<nums2.length){
            if(nums1[i]<nums2[j]) {
                i++;
            } else if(nums1[i]>nums2[j]){
                j++;
            }else{
                arr[index++] = nums1[i];
                i++;
                j++;
            }
        }
        return Arrays.copyOfRange(arr,0,index);
    }
}

11. 盛最多水的容器

暴力写法:

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

使用双指针来优化:

class Solution {
    public int maxArea(int[] height) {
        int maxArea = 0;
        int area = 0;
        int i=0;
        int j = height.length-1;
        while (i<j){
            area = (j-i)* Math.min(height[i],height[j]);
            maxArea = Math.max(maxArea,area);
            if(height[i]<height[j]){
                i++;
            }else{
                j--;
            }
        }
        return maxArea;
    }
}

844. 比较含退格的字符串

class Solution {
    public boolean backspaceCompare(String S, String T) {
        //将#号和要删除的元素删除后,看剩下的元素是否相同
        String str1 = deleteChar(S);
        String str2 = deleteChar(T);
        return str1.equals(str2);
    }

    private String deleteChar(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)!='#'){
               stack.push(s.charAt(i));
            }else if(!stack.isEmpty()){
                stack.pop();
            }
        }
        return stack.toString();
    }
}

349. 两个数组的交集

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        HashSet<Integer> set1 = new HashSet<>();
        HashSet<Integer> set2 = new HashSet<>();
        for(int i=0;i<nums1.length;i++){
            set1.add(nums1[i]);
        }
        
        for(int i=0;i<nums2.length;i++){
            if(set1.contains(nums2[i])){
                set2.add(nums2[i]);
            }
        }
        int len = set2.size();
        int[] arr = new int[len];
        int i=0;
        for(Integer value :set2){
            arr[i++] = value;
        }
        return arr;
    }
}

16. 最接近的三数之和

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        if(nums.length==0 || nums==null) return 0;
        int res = nums[0]+nums[1]+nums[2];
        Arrays.sort(nums);
        for(int i=0;i<nums.length;i++){
            int left = i+1;
            int right = nums.length-1;
            while (left<right){
                int sum = nums[left]+nums[right]+nums[i];
                if(sum>target){
                    right--;
                }else{
                    left++;
                }
                if(Math.abs((sum-target))<Math.abs((res-target))){
                    res = sum;
                }
            }
        }
        return res;
    }
}

80. 删除排序数组中的重复项 II

class Solution {
    public int removeDuplicates(int[] nums) {
         if(nums.length==0 || nums==null) return 0;
         int count = 1;
         int i=1;
         for(int j=1;j<nums.length;j++){
             if(nums[j]==nums[j-1]){
                 count++;
             }else if(nums[j]!=nums[j-1]){
                 count = 1;
             }
             if(count<=2){
                 nums[i] = nums[j];
                 i++;
             }
         }
         return i; 
    }
}

86. 分隔链表

class Solution {
    public ListNode partition(ListNode head, int x) {
        ListNode dummy1 = new ListNode(0);
        ListNode cur1 = dummy1;
        ListNode dummy2 = new ListNode(0);
        ListNode cur2 = dummy2;
        ListNode cur = head;

        while (cur!=null){
            if(cur.val<x){
                cur1.next = cur;
                cur1 = cur1.next;
            }else{
                cur2.next = cur;
                cur2 = cur2.next;
            }
            cur = cur.next;
        }
        // 踩坑
        // 这个不写会导致链表成环:比如【1,3,5,6,2】这个链表,假设 x=3,则可得到两个链表分别是【1,2】和【3,5,6】,
        // 但此时右链表的尾部,即6的尾部仍指向2,如果不把右链表的尾部置为None,
        // 最后就会得到 1->2->3->5->6->2 这个链表,在节点2处成环。
        // 因此必须将右链表尾部手动置为None,实现断链,最后得到 1->2->3->5->6->None。
        cur2.next = null;

        cur1.next = dummy2.next;
        return dummy1.next;
    }
}

287. 寻找重复数

class Solution {
    public int findDuplicate(int[] nums) {
        if(nums.length==0 || nums==null) return 0;
        int i=0;
        while (i<nums.length){
            if(nums[i]==i){
                i++;
                continue;
            }else{
                int temp = nums[i];
                nums[i] = nums[temp];
                nums[temp] = temp;
            }
            if(nums[i]==nums[nums[i]]) return nums[i];
        }
        return -1;
    }
}

977. 有序数组的平方

暴力法:

class Solution {
    public int[] sortedSquares(int[] A) {
        int[] arr = new int[A.length];
        for(int i=0;i<A.length;i++){
            arr[i] = A[i]*A[i];
        }
        Arrays.sort(arr);
        return arr;
    }
}

优化方法:要求保持数组递增或者递减顺序,可以使用合并两个排序数组的思想

class Solution {
    //合并两个有序数组的思想
    public int[] sortedSquares(int[] A) {
        //要么是最左边的元素最大,要么是最右边的元素最大
        int i=0;
        int j = A.length-1;
        
        int[] arr = new int[A.length];
        int k = A.length-1;
        while (i<=j){
            if(A[i]*A[i]<A[j]*A[j]){
                arr[k--] = A[j]*A[j];
                j--;
            }else{
                arr[k--] = A[i]*A[i];
                i++;
            }
        }
        return arr;
    }
}

424. 替换后的最长重复字符

class Solution {
    public int characterReplacement(String s, int k) {
        int start = 0;
        int max = 0;
        int[] count = new int[26];
        for(int end =0;end<s.length();end++){
            //统计窗口每个字符出现的次数
            count[s.charAt(end)-'A']++;
            max = Math.max(max,count[s.charAt(end)-'A']);
            //如果窗口内要替换的字符大于K时,就需要将窗口收缩
            if(end-start+1-max>k){
                count[s.charAt(start)-'A']--;
                start++;
            }
        }
        return s.length()-start;
    }
}

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

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int start = 0;
        int res = 0;
        HashMap<Character,Integer> map = new HashMap<>();
        for(int end = 0;end<s.length();end++){
            if(map.containsKey(s.charAt(end))){
                start = Math.max(start,map.get(s.charAt(end))+1);
            }
            //即便包含也需要添加到map中,这样才能键相同值覆盖 
            map.put(s.charAt(end),end);
            
            res = Math.max(end-start+1,res);
        }
        return res;
    }
}

986. 区间列表的交集

class Solution {
    public int[][] intervalIntersection(int[][] A, int[][] B) {
        int i=0;
        int j=0;
        int maxStart;
        int minEnd;
        int index = 0;
        int[][] arr = new int[A.length+B.length][];
        while (i<A.length && j<B.length){
            maxStart = Math.max(A[i][0],B[j][0]);
            minEnd = Math.min(A[i][1],B[j][1]);
            if(maxStart<=minEnd){
                arr[index++] = new int[]{maxStart,minEnd};
            }
            if(A[i][1]>B[j][1]){
                j++;
            }else{
                i++;
            }
        }
        arr = Arrays.copyOf(arr, index);
        return arr;
    }
}

56. 合并区间

class Solution {
    List<int[]> list = new ArrayList<>();
    public int[][] merge(int[][] intervals) {
        if(intervals.length==0 || intervals==null) {
            return list.toArray(new int[0][]);
        }
        //对数组中的头元素进行排序
        Arrays.sort(intervals, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0]-o2[0];
            }
        });
        int i=0;
        while (i<intervals.length){
            int start = intervals[i][0];
            int end = intervals[i][1];
            //考虑要合并的情况:这个地方的处理是我需要学习的地方
            //当出现需要合并的情况时,就需要更新end
            while (i<intervals.length-1 && end>=intervals[i+1][0]){
                i++;
                end = Math.max(end,intervals[i][1]);
            }
            i++;
            list.add(new int[]{start,end});
        }
        return list.toArray(new int[0][]);
    }
}

1248. 统计「优美子数组」

暴力解法:超出时间限制

思路就是使用滑动窗口,start和end分别指向窗口的头尾,不断的移动end指针,判断窗口内的元素的奇数的个数是否等于k,如果等于就让计数加1,当end到达末尾时,让start向后移动,然后重置count的值。

class Solution {
    public static void main(String[] args) {
        int[] arr = new int[]{2,2,2,1,2,2,1,2,2,2};
        System.out.println(numberOfSubarrays(arr, 2));
    }
    public static int numberOfSubarrays(int[] nums, int k) {
        if(nums.length==0 || nums==null) return 0;
        int start=0;
        int res = 0;
        while (start<nums.length ){
            int end = start;
            int count = 0;
            while (end<nums.length){
                if(nums[end]%2==1){
                    count++;
                }
                end++;
                if(count==k){
                    res++;
                }
            }
            start++;
        }
        return res;
    }
}
class Solution {
    public int numberOfSubarrays(int[] nums, int k) {
        int left = 0;
        int right = 0;
        int oddCnt = 0;
        int res = 0;
        while (right < nums.length) {
            //注意这儿,不管是奇数还是偶数,都会使得right指针后移
            if (nums[right++] % 2 == 1) {
                oddCnt++;
            }
            if (oddCnt == k) {
            	//统计第k个奇数右边的偶数个数
                int rightCount = 0;
                while (right < nums.length && nums[right]%2==0) {
                    rightCount++;
                    right++;
                }
				
				//统计第一个奇数左边的偶数个数
                int leftCount = 0;
                while (nums[left] %2==0) {
                    leftCount++;
                    left++;
                }

                res += (leftCount + 1) * (rightCount + 1);
                //让头指针右移,统计下一轮
                left++;
                oddCnt--;
            }
        }
        return res;
    }
}

567. 字符串的排列

先对短的字符串进行排序,然后截取长的字符串的子串后进行排序,判断两个排序后的子串和短的字符串是否相同

public class Solution {
    public static void main(String[] args) {
        String s1  = "ab";
        String s2 = "eidbaooo";
    }
    public boolean checkInclusion(String s1, String s2) {
        s1 = sort(s1);
        for(int i=0;i<=s2.length()-s1.length();i++){
            //不可以先排序再截取,只能先截取再排序
           if(s1.equals(sort(s2.substring(i, i + s1.length())))){
               return true;
           }
        }
        return false;
    }
    public String sort(String s) {
        char[] t = s.toCharArray();
        Arrays.sort(t);
        //String(StringBuffer buffer);通过StringBuffer数组构造字符串对象
        //String(char[] value); 通过char数组构造字符串对象
        return new String(t);
    }
}

方法二:使用hash表统计s1中每个字符出现的频率,判断s2中子串字符出现的频率和s1中是否相同。

public class Solution {
    public static void main(String[] args) {
        String s1  = "ab";
        String s2 = "eidbaooo";
    }
    public boolean checkInclusion(String s1, String s2) {
        // Map.getOrDefault(key,默认值);
        // Map中会存储一一对应的key和value。
        // 如果 在Map中存在key,则返回key所对应的的value。
        // 如果 在Map中不存在key,则返回默认值。
        // 解题思路:如果s1是s2子串的全排列,那么s1和s2的子串中的每个字符出现的次数应该相同

        HashMap<Character,Integer> map1 = new HashMap<>();
        //统计s1的每个字符的次数
        for(int i=0;i<s1.length();i++){
            map1.put(s1.charAt(i), map1.getOrDefault(s1.charAt(i),0)+1);
        }
        for(int i=0;i<=s2.length()-s1.length();i++){
            HashMap<Character,Integer> map2 = new HashMap<>();
            //统计s2的子串的每个字符的次数
            for(int j=0;j<s1.length();j++ ){
                map2.put(s2.charAt(i+j),map2.getOrDefault(s2.charAt(i+j),0)+1);
            }
            //判断两个字符串具有相同频率的相同字符
            if(matches(map1,map2)){
                return true;
            }
        }
        return false;
    }

   private boolean matches(HashMap<Character, Integer> map1, HashMap<Character, Integer> map2){
        for(Character key : map1.keySet()){
            if(map1.get(key) - map2.getOrDefault(key,-1)!=0){
                return false;
            }
        }
        return true;
    }
}

方法3:使用数组统计每个字符出现的频率

public class Solution {
    public static void main(String[] args) {
        String s1  = "ab";
        String s2 = "eidbaooo";
    }
    public boolean checkInclusion(String s1, String s2) {
        int[] arr1 = new int[26];
        for (int i = 0; i < s1.length(); i++) {
            arr1[s1.charAt(i) - 'a']++;
        }

        for (int i = 0; i <= s2.length() - s1.length(); i++) {
            int[] arr2 = new int[26];
            for (int j = 0; j < s1.length(); j++) {
                arr2[s2.charAt(i+j) - 'a']++;
            }
            if(matches(arr1,arr2)){
                return true;
            }
        }
        return false;
    }

    private boolean matches(int[] arr1, int[] arr2) {
        for(int i=0;i<arr1.length;i++){
            if(arr1[i]!=arr2[i]){
                return false;
            }
        }
        return true;
    }
}

1004. 最大连续1的个数 III

class Solution {
    public int longestOnes(int[] A, int K) {
        //使用滑动窗口
        int start = 0;
        int maxLength = 0;
        int count = 0;
        for(int end=0;end<A.length;end++){
            if(A[end]==0){
                count++;
            }
            if(count>K){
                if(A[start]==0) count--;
                start++;
            }
            maxLength = Math.max(maxLength,end-start+1);
        }
        return maxLength;
    }
}

209. 长度最小的子数组

暴力法:

class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        if(nums.length==0 || nums==null) return 0;
        int maxLength = Integer.MAX_VALUE;
        for(int i=0;i<nums.length;i++){
            int sum = 0;
            for(int j=i;j<nums.length;j++){
                sum += nums[j];
                if(sum>=s){
                    maxLength = Math.min(maxLength,j-i+1);
                    break;
                }
            }
        }
        return maxLength==Integer.MAX_VALUE ? 0:maxLength;
    }
}

剑指 Offer 53 - II. 0~n-1中缺失的数字

class Solution {
    public int missingNumber(int[] nums) {
        int m = 0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=m) break;
            m++;
        }
        return m ;
    }
}

378. 有序矩阵中第K小的元素

暴力法:

class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        int[] arr = new int[matrix.length*matrix[0].length];
        int index = 0;
        for(int i=0;i<matrix.length;i++){
            for(int j=0;j<matrix[0].length;j++){
                arr[index++] = matrix[i][j];
            }
        }
        Arrays.sort(arr);
        return arr[k-1];
    }
}

718. 最长重复子数组

class Solution {
    public int findLength(int[] A, int[] B) {
        int maxLength = 0;
        for(int i=0;i<A.length;i++){
            for(int j=0;j<B.length;j++){
                int posA = i;
                int posB = j;
                while (posA<A.length && posB<B.length && A[posA]==B[posB]){
                    posA++;
                    posB++;
                }
                maxLength = Math.max(maxLength,posA-i);
            }
        }
        return maxLength;
    }
}

867. 转置矩阵

class Solution {
    public int[][] transpose(int[][] A) {
        int m = A.length;
        int n = A[0].length;
        int[][] arr = new int[n][m];
        for(int i=0;i<m;i++){
            for (int j=0;j<n;j++){
               arr[j][i] = A[i][j];
            }
        }
        return arr;
    }
}
©️2020 CSDN 皮肤主题: 点我我会动 设计师:上身试试 返回首页