二刷代码随想录|Java版|数组

理论

对于数组,Java里面也有,int[] nums。
如何求长度:nums.length。
相关知识点:https://www.runoob.com/java/java-array.html
HashMap:https://www.runoob.com/java/java-hashmap.html

1.1 二分查找

注意right的取值,区间是闭是开。

1.2 快慢指针(删除元素)

class Solution {
    public int removeElement(int[] nums, int val) {
        // 快慢指针
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
            if (nums[fastIndex] != val) {
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }
        }
        return slowIndex;
    }
}

1.3 双端指针

class Solution {
    public int[] sortedSquares(int[] nums) {
        int n = nums.length;
        int[] ans = new int[n];
        for (int i = 0, j = n - 1, pos = n - 1; i <= j;) {
            if (nums[i] * nums[i] > nums[j] * nums[j]) {
                ans[pos] = nums[i] * nums[i];
                ++i;
            } else {
                ans[pos] = nums[j] * nums[j];
                --j;
            }
            --pos;
        }
        return ans;
    }
}

1.4 滑动窗口

有固定窗口大小,和变长窗口两种。

  • 我们在字符串 S 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right]称为一个「窗口」。
  • 我们先不断地增加 right 指针扩大窗口 [left, right],直到窗口中的字符串符合要求(包含了T中的所有字符)。
  • 此时,我们停止增加 right,转而不断增加 left 指针缩小窗口 [left,right],直到窗口中的字符串不再符合要求(不包含 T 中的所有字符了)。同时,每次增加 left,我们都要更新一轮结果。
  • 重复第2和第3步,直到 right 到达字符串 S 的尽头

滑动窗口知识点

习题

1|704. 二分查找|分为左闭右闭,左闭右开。

class Solution {
    public int search(int[] nums, int target) {
        // 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
        if (target < nums[0] || target > nums[nums.length - 1]) {
            return -1;
        }
        int left = 0, right = nums.length - 1;//right=nums.length时,while是<,right=mid
        while (left <= right) {
            int mid = left + ((right - left) >> 1);//位运算显然更快一些,也更高级。
            if (nums[mid] == target)
                return mid;
            else if (nums[mid] < target)
                left = mid + 1;
            else if (nums[mid] > target)
                right = mid - 1;
        }
        return -1;
    }
}

2|35. 搜索插入位置

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid] == target)
                return mid;
            else if (nums[mid] < target)
                left = mid + 1;
            else if (nums[mid] > target)
                right = mid - 1;
        }
        return left;
    }
}

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

class Solution {
    public int[] searchRange(int[] nums, int target) {
        if (nums.length==0||target < nums[0] || target > nums[nums.length - 1]) {
            return new int[]{-1, -1};
        }
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + ((right - left) >> 1);
            if (nums[mid] == target){
                int l=mid-1, r=mid+1;
                for(int i=mid-1; i>=0; i--){
                    if(nums[l]==target) l--;
                }
                for(int i=mid+1; i<nums.length; i++){
                    if(nums[r]==target) r++;
                }
                return new int[]{l+1, r-1};

            }
            else if (nums[mid] < target)
                left = mid + 1;
            else if (nums[mid] > target)
                right = mid - 1;
        }
        return new int[]{-1, -1};
    }
}

4|69. x 的平方根 |不允许使用内置的求平方根的函数

转化思路k*k==x

class Solution {
    public int mySqrt(int x) {
        int l = 0, r = x, ans = -1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if ((long) mid * mid <= x) {
                ans = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        return ans;
    }
}

5|367. 有效的完全平方数

谨记用long,因为相乘可能会过大超过int可表示的范围。

class Solution {
    public boolean isPerfectSquare(int num) {
        if(num==1){
            return true;
        }
        int left=1, right=num-1;
        while(left<=right){
            int mid = left + ((right - left) >> 1);
            System.out.print(mid+" ");
            if((long)mid*mid==num){
                return true;
            }else if((long)mid*mid<num){
                left=mid+1;
            }else if((long)mid*mid>num){
                right=mid-1;
            }
        }
        return false;

    }
}

6|27. 移除元素|快慢指针的思路

暴力解法

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

快慢指针

class Solution {
    public int removeElement(int[] nums, int val) {
        // 快慢指针
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
            if (nums[fastIndex] != val) {
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }
        }
        return slowIndex;
    }
}

相向双指针法:元素的顺序可以改变

/**
* 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
* 时间复杂度:O(n)
* 空间复杂度:O(1)
*/
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int leftIndex = 0;
        int rightIndex = nums.size() - 1;
        while (leftIndex <= rightIndex) {
            // 找左边等于val的元素
            while (leftIndex <= rightIndex && nums[leftIndex] != val){
                ++leftIndex;
            }
            // 找右边不等于val的元素
            while (leftIndex <= rightIndex && nums[rightIndex] == val) {
                -- rightIndex;
            }
            // 将右边不等于val的元素覆盖左边等于val的元素
            if (leftIndex < rightIndex) {
                nums[leftIndex++] = nums[rightIndex--];
            }
        }
        return leftIndex;   // leftIndex一定指向了最终数组末尾的下一个元素
    }
};

7|26. 删除有序数组中的重复项

跟上一题按理来说,思路应该是一样的。
先暴力。

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

快慢指针

class Solution {
    public int removeDuplicates(int[] nums) {
        // 快慢指针
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
            if (nums[fastIndex] != nums[slowIndex]) {
                nums[++slowIndex] = nums[fastIndex];
            }
        }
        // for(int i=0; i
        //     System.out.print(nums[i]+" ");
        // }
        return slowIndex+1;
    }
}

8|283. 移动零

class Solution {
    public void moveZeroes(int[] nums) {
// 快慢指针
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
            if (nums[fastIndex] != 0) {
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }
        }
        for(int i=slowIndex; i>=0&&i<nums.length; i++){
            nums[i]=0;
        }
    }
}

9|844. 比较含退格的字符串

class Solution {
    public boolean backspaceCompare(String S, String T) {
        int i = S.length() - 1, j = T.length() - 1;
        int skipS = 0, skipT = 0;

        while (i >= 0 || j >= 0) {
            while (i >= 0) {
                if (S.charAt(i) == '#') {
                    skipS++;
                    i--;
                } else if (skipS > 0) {
                    skipS--;
                    i--;
                } else {
                    break;
                }
            }
            while (j >= 0) {
                if (T.charAt(j) == '#') {
                    skipT++;
                    j--;
                } else if (skipT > 0) {
                    skipT--;
                    j--;
                } else {
                    break;
                }
            }
            if (i >= 0 && j >= 0) {
                if (S.charAt(i) != T.charAt(j)) {
                    return false;
                }
            } else {
                if (i >= 0 || j >= 0) {
                    return false;
                }
            }
            i--;
            j--;
        }
        return true;
    }
}

10|977. 有序数组的平方

Array包装类。

class Solution {
    public int[] sortedSquares(int[] nums) {
       int[] ans = new int[nums.length];
        for (int i = 0; i < nums.length; ++i) {
            ans[i] = nums[i] * nums[i];
        }
        Arrays.sort(ans);//利用Array这个包装类来处理。
        return ans;
    }
}

双指针

class Solution {
    public int[] sortedSquares(int[] nums) {
       int left=0, right=nums.length-1, ans=nums.length-1;
       int[] ansNums= new int[nums.length];
       while(left<=right){
           if(nums[left]*nums[left]>nums[right]*nums[right]){
               ansNums[ans] = nums[left]*nums[left];
               ans--;
               left++;
           }else{
                ansNums[ans] = nums[right]*nums[right];
                ans--;
                right--;
           }
       }
       return ansNums;
    }
}

11|209. 长度最小的子数组

整个思路就是先让right大胆地去搜索,之后让left去收敛。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        if(nums.length==0){
            return 0;
        }
        int left=0, right=0;
        int sum=0;
        int res=100000+5;
        for(;right<nums.length;right++){
            sum += nums[right];
            while(sum>=target){
                res = Math.min(res, right-left+1);
                sum -= nums[left];
                left++;
            }
        }
        return res==100000+5? 0:res;

    }
}

12|904. 水果成篮

用到了HashMap!

class Solution {
    public int totalFruit(int[] fruits) {
        int n = fruits.length;
        Map<Integer, Integer> cnt = new HashMap<Integer, Integer>();

        int left = 0, ans = 0;
        for (int right = 0; right < n; ++right) {
            cnt.put(fruits[right], cnt.getOrDefault(fruits[right], 0) + 1);
            while (cnt.size() > 2) {
                cnt.put(fruits[left], cnt.get(fruits[left]) - 1);
                if (cnt.get(fruits[left]) == 0) {
                    cnt.remove(fruits[left]);
                }
                ++left;
            }
            ans = Math.max(ans, right - left + 1);
        }
        return ans;
    }
}

13|76. 最小覆盖子串

太难了。

class Solution {
    Map<Character, Integer> ori = new HashMap<Character, Integer>();
    Map<Character, Integer> cnt = new HashMap<Character, Integer>();

    public String minWindow(String s, String t) {
        int tLen = t.length();
        for (int i = 0; i < tLen; i++) {
            char c = t.charAt(i);
            ori.put(c, ori.getOrDefault(c, 0) + 1);
        }
        int l = 0, r = -1;
        int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;
        int sLen = s.length();
        while (r < sLen) {
            ++r;
            if (r < sLen && ori.containsKey(s.charAt(r))) {
                cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
            }
            while (check() && l <= r) {
                if (r - l + 1 < len) {
                    len = r - l + 1;
                    ansL = l;
                    ansR = l + len;
                }
                if (ori.containsKey(s.charAt(l))) {
                    cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);
                }
                ++l;
            }
        }
        return ansL == -1 ? "" : s.substring(ansL, ansR);
    }

    public boolean check() {
        Iterator iter = ori.entrySet().iterator(); 
        while (iter.hasNext()) { 
            Map.Entry entry = (Map.Entry) iter.next(); 
            Character key = (Character) entry.getKey(); 
            Integer val = (Integer) entry.getValue(); 
            if (cnt.getOrDefault(key, 0) < val) {
                return false;
            }
        } 
        return true;
    }
}

14|76. 最小覆盖子串

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] res = new int[n][n];
        int val=1;
        for(int k=0; k<n/2+1; k++){
            for(int c=k; c<n-k; c++){
                res[k][c] = val;
                val++;
            }
            for(int r=k+1; r<n-k; r++){
                res[r][n-k-1] = val;
                val++;
            }
            for(int c=n-k-2; c>=k; c--){
                res[n-k-1][c] = val;
                val++;
            }
            for(int r=n-k-2; r>=k+1; r--){
                res[r][k] = val;
                val++;
            }
        }
        return res;

    }
}

15|54. 螺旋矩阵

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        int n = matrix.length;
        int m = matrix[0].length;
        int nk=0, mk=0;
        List<Integer> res = new ArrayList<Integer>();
        for(int val=0; val<n*m; ){
            for(int c=mk; c<m-mk&&val<n*m; c++){
                res.add(matrix[nk][c]);
                val++;
            }
            for(int r=nk+1; r<n-nk&&val<n*m; r++){
                res.add(matrix[r][m-mk-1]);
                val++;
            }
            for(int c=m-mk-2; c>=mk&&val<n*m; c--){
                res.add(matrix[n-nk-1][c]);
                val++;
            }
            for(int r=n-nk-2; r>=nk+1&&val<n*m; r--){
                res.add(matrix[r][mk]);
                val++;
            }
            nk++;
            mk++;
        }
        return res;
    }
}

你可能感兴趣的:(二刷代码随想录,java,开发语言)