二分查找
暴力解法时间复杂度: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 的连续地址空间,而是四条连续的地址空间组成!」
理解數組的各種方法和邊界處理