LeeCode刷题简记(四)

数组矩阵类      LeeCode数据结构题库

Solution11盛最多水的容器、Solution283移动零、Solution169多数元素、Solution724寻找数组的中心下标、Solution1013将数组分成和相等的三个部分、Solution74搜索二维矩阵、Solution240搜索二维矩阵Ⅱ、Solution209长度最小的子数组、Solution905按奇偶排序数组、

摩尔投票法,前缀和法,寻找切割点,滑动窗口

Solution11盛最多水的容器

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

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

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

选择排序比较,非常慢时间复杂度超出限制

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

双指针法  时间复杂度On 

想法:往后或往前试长度的时候可以把小于当前最开始的值当作标尺,比更长的还要矮就可以直接跳过,每次用math.max挑选出来。

public int maxArea(int[] height) {
        int maxArea = 0;
        int l = 0;
        int r = height.length - 1;
        while (l < r) {
            if (height[l] <= height[r]){
                int low = height[l];
                int area = low * (r - l);
                maxArea = Math.max(area,maxArea);
                while (l < r && height[l] <= low){
                    l++;
                }
            }else {
                int low = height[r];
                int area = low * (r - l);
                maxArea = Math.max(area,maxArea);
                while (l < r && height[r] <= low){
                    r--;
                }
            }
        }
        return maxArea;
    }

Solution169多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

排序法直接排序找中间值,中间值必是众数

public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }

摩尔投票法  

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

Solution283移动零

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

插入排序 元素稳定 但是时间复杂度为On*2

public class S283移动零 {
    public void moveZeroes(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0){
                for (int j = i; j > 0 && nums[j - 1] == 0; j--){
                    int temp = nums[j];
                    nums[j] = nums[j - 1];
                    nums[j - 1] = temp;
                }
            }
        }
    }
}

双指针法 快且稳

public void moveZeroes01(int[] nums) {
        int k = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0){
                int temp = nums[i];
                nums[i] = nums[k];
                nums[k] = temp;
                k++;
            }
        }
    }
}

 Solution724寻找数组的中心下标

给你一个整数数组 nums ,请计算数组的 中心下标 。

数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。

如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。

如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。

前缀和法

遍历总和,右边就等于总和减左边和,从0开始计数左边和与右边和相等即可 。

public int pivotIndex(int[] nums) {
        int sum = 0;
        for(int num : nums) {
            sum += num;
        }
        int leftSum = 0;
        int rightSum = 0;
        for (int i = 0; i < nums.length; i++) {
            if (i == 0) {
                leftSum = 0;
            }else {
                leftSum += nums[i - 1];
            }
            rightSum = sum - leftSum - nums[i];//当前数右边
            if (leftSum == rightSum){
                return i;
            }
        }
        return -1;
    }

 Solution1013将数组分成和相等的三个部分

给你一个整数数组 arr,只有可以将其划分为三个和相等的 非空 部分时才返回 true,否则返回 false。

形式上,如果可以找出索引 i + 1 < j 且满足 (arr[0] + arr[1] + ... + arr[i] == arr[i + 1] + arr[i + 2] + ... + arr[j - 1] == arr[j] + arr[j + 1] + ... + arr[arr.length - 1]) 就可以将数组三等分。

 找切割点,3整除数组总和,找到一个和就切一下,找到第二组定位第三组。

public boolean canThreePartsEqualSum(int[] arr) {
        int sum = 0;
        for (int num : arr){
            sum += num;
        }
        if (sum % 3 != 0){
            return false;
        }
        int key = sum / 3;
        int i = 0;
        int part = 0;
        while (i < arr.length) {
            part += arr[i];
            if (part == key){//等于就强制退出
                break;
            }
            i++;
        }
        if (part != key) {//没有就返回false
            return false;
        }
        part = 0;
        //找第二组定位第三组
        int j = i + 1;
        while (j < arr.length - 1){//第三组至少有一个元素存在
            part += arr[j];
            if (part == key) {//第二组找到就不找第三组
                return true;
            }
            j++;
        }
        return false;
    }

双指针法

public boolean canThreePartsEqualSum01(int[] arr) {
        int sum = 0;
        for (int num : arr){
            sum += num;
        }
        if (sum % 3 != 0){
            return false;
        }
        int key = sum / 3;
        int left = 0;
        int leftSum = arr[left];
        int right = arr.length - 1;
        int rightSum = arr[right];
        while (left + 1 < right){//左小于右的情况下找到第一组和第三组
            if (leftSum == key && rightSum == key){
                return true;
            }
            if (leftSum != key){
                leftSum += arr[++left];
            }
            if (rightSum != key){
                rightSum += arr[--right];
            }
        }
        return false;
    }

Solution74搜索二维矩阵 

编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:

每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。

 将二维数组换算成一维数组进行判断,除列与对列取余,然后用二分查找。

public boolean searchMatrix(int[][] matrix, int target) {
        int R = matrix.length;
        int C = matrix[0].length;
        int left = 0;
        int right = R * C - 1;
        int mid = (left + right) / 2;
        while (true) {
            if (matrix[mid / C][mid % C] < target){
                left = mid + 1;
            } else if (matrix[mid / C][mid % C] > target){
                right = mid - 1;
            }else {
                return true;
            }
            if (left > right ){//越界则没有
                return false;
            }
            mid = (left + right) / 2;//每次都要重置mid
        }
    }

Solution240搜索二维矩阵Ⅱ

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

每行的元素从左到右升序排列。
每列的元素从上到下升序排列。

第一行右边不一定比第二行左边大,无法展开成一维数组。

 从矩阵左下角往右上走去找,往上一定小往右一定大。

public boolean searchMatrix(int[][] matrix, int target) {
        //设长宽,起始在左下
        int row = matrix.length;
        int col = matrix[0].length;
        int x = row - 1;
        int y = 0;
        while (true){
            if (x<0 || y >= col){
                return false;
            }
            //大了往上走  小了往右走
            if (matrix[x][y] > target){
                x--;
            }else if (matrix[x][y] < target){
                y++;
            }else {
                return true;
            }
        }
    }

Solution209长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

滑动窗口法本质还是双指针法,小于目标后标后扩,满足目标让前标延后。

public int minSubArrayLen(int s, int[] nums) {
        int left = 0;
        int right = 0;
        int sum = nums[right];
        int length = 0;
        int minLength = nums.length;
        while (true) {
            if (sum < s) {
                if (++right >= nums.length){
                    break;
                }
                sum +=nums[right];
            }else {
                length = right - left + 1;
                minLength = minLength < length ? minLength : length;
                sum -= nums[left];
                left++;
                if (left > right){
                    break;
                }
            }
        }
        if (length == 0) return 0;//防止没找到用初始值验证
        return minLength;
    }

Solution905按奇偶排序数组

给定一个非负整数数组 A,返回一个数组,在该数组中, A 的所有偶数元素之后跟着所有奇数元素。

你可以返回满足此条件的任何数组作为答案

选择排序  交换奇偶    时间复杂度较高

public int[] sortArrayByParity(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] % 2 == 1){
                for (int j = i + 1; j < nums.length; j++) {
                    if (nums[j] % 2 == 0) {
                        int temp = nums[i];
                        nums[i] = nums[j];
                        nums[j] = temp;
                        break;
                    }
                }
            }
        }
        return nums;
    }

双指针法  前后同时移动

public int[] sortArrayByParity01(int[] A) {
        int l = 0;
        int r = A.length - 1;
        while (l < r) {
            //左奇右偶直接换
            if (A[l] % 2 == 1 && A[r] % 2 == 0){
                int temp = A[l];
                A[l] = A[r];
                A[r] = temp;
            }else if (A[l] % 2 == 0 && A[r] % 2 == 1){
                //左偶右奇指针都动
                l++;
                r--;
            }else if (A[l] % 2 == 1 && A[r] % 2 == 1){
                r--;
            }else {
                l++;
            }
        }
        return A;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值