数组:二分法和邊界問題,雙指針,模擬

二分查找

暴力解法时间复杂度:O(n)
二分法时间复杂度:O(logn)

编号35:搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:
输入: [1,3,5,6], 5
输出: 2

示例 2:
输入: [1,3,5,6], 2
输出: 1

示例 3:
输入: [1,3,5,6], 7
输出: 4

示例 4:
输入: [1,3,5,6], 0
输出: 0

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

在这里插入图片描述

優化官方代碼right為邊界

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int n = nums.size();
        int left = 0;
        int right = n - 1; // 定义target在左闭右闭的区间里,[left, right] 
        while (left <= right) { // 当left==right,区间[left, right]依然有效
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else { // nums[middle] == target
                return middle;
            }
        }
        // 分别处理如下四种情况
        // 目标值在数组所有元素之前  [0, -1]
        // 目标值等于数组中某一个元素  return middle;
        // 目标值插入数组中的位置 [left, right],return  right + 1
        // 目标值在数组所有元素之后的情况 [left, right], return right + 1
        return right + 1;
    }
};

題解:
二分查找,查不到返回插入的位置,比較難處理邊界問題,,,需要舉例説明,自己寫的代碼太粗糙了

双指针法(一次邊厲)

暴力解法时间复杂度:O(n^2)
双指针时间复杂度:O(n)

(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组和链表操作的面试题,都使用双指针法。

移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并「原地」修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。

示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

class Solution {
    public int removeElement(int[] nums, int val) {
        int l = 0;
        int r = nums.length;
        while(l<r){
            if(nums[l] == val){
                nums[l] = nums[r-1];
                r--; 
            }else l++;

        }
        return l;
    }
}

滑动窗口

暴力解法时间复杂度:O(n^2)
滑动窗口时间复杂度:O(n)
「就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果」。

长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int len = nums.length+1;
        int sum = 0 ;
        int origin = 0;
        for(int i =0;i<nums.length;i++){
            sum += nums[i]; 
            while(sum >= target){
                int sublen = (i-origin+1);//length of substring
                len = len<sublen?len:sublen;
                sum -= nums[origin];
                origin++;
            }
        }
        return len > nums.length?0:len ;
    }
}

在这里插入图片描述
題解:

在这里插入图片描述

class Solution {
    public int[][] generateMatrix(int n) {
        int left = 0;
        int right = n-1;
        int top = 0;
        int bottom = n-1;
        int [][]res = new int [n][n];
        int  count =1;
        while(left<=right && top<=bottom){
            //l->r
            for(int l = left ;l<= right ;l++){
                res[top][l]=count;
                count++;
            }
            //t->b
            for(int t = top+1 ;t<= bottom ;t++){
                res[t][right]=count;
                count++;
            }

            if(left<right && top<bottom){
                //r->l
                for(int l = right-1;l>left;l--){
                    res[bottom][l]= count;
                    count++;
                }
                //b->t
                for(int b = bottom ; b>top ;b--){
                    res[b][left]=count;
                    count++;
                }
            
            }
                left++;
                right--;
                top++;
                bottom--;

        }

        return res;

    }
}

題解:按層解析,注意
這種做法是
從右往左和從下到上都不能碰邊界
上和右都需要碰邊,但是反過來也可以,有機會再實現
ps:官方的似乎工整點
在这里插入图片描述

總結:

「数组是存放在连续内存空间上的相同类型数据的集合。」
大家如果使用C++的话,要注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组。

「数组的元素是不能删的,只能覆盖。」
「那么二维数组在内存的空间地址不是连续的么?」
所以a[3][4]在「二维数据在内存中不是 3*4 的连续地址空间,而是四条连续的地址空间组成!」

理解數組的各種方法和邊界處理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值