一 数组
1 二分查找
704. 二分查找
-
给定一个
n
个元素有序的(升序)整型数组nums
和一个目标值target
,写一个函数搜索nums
中的target
,如果目标值存在返回下标,否则返回-1
。 -
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9 输出: 4 解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2 输出: -1 解释: 2 不存在 nums 中因此返回 -1
-
//左闭右开 int search(vector<int>& nums, int target) { int left = 0; int right = nums.size(); while(left < right) //left = right 是没有意义的 { int mid = left+ ((right -left)>>1) ; // >> 优先级 if(nums[mid] > target) { right = mid; } else if(nums[mid] < target) { left = mid+1; }else{ return mid; } } return -1; } //左闭右闭 int search(vector<int>& nums, int target) { int left = 0; int right = nums.size()-1; while(left <= right) { int mid = left+ ((right -left)>>1) ; // >> 优先级 if(nums[mid] > target) { right = mid-1; } else if(nums[mid] < target) { left = mid+1; }else{ return mid; } } return -1; }
35. 搜索插入位置
-
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为
O(log n)
的算法。 -
示例 1:
输入: nums = [1,3,5,6], target = 5 输出: 2
示例 2:
输入: nums = [1,3,5,6], target = 2 输出: 1
示例 3:
输入: nums = [1,3,5,6], target = 7 输出: 4
-
int searchInsert(vector<int>& nums, int target) { int left = 0; int right = nums.size(); while(left< right) { int mid = left + ((right - left) >> 1); if(nums[mid] > target) { right = mid; }else if(nums[mid] < target) { left = mid +1; }else{ return mid; } } return right ; }
-
当 left = right 时,left 就是要插入的位置
34. 在排序数组中查找元素的第一个和最后一个位置
-
给你一个按照非递减顺序排列的整数数组
nums
,和一个目标值target
。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值
target
,返回[-1, -1]
。你必须设计并实现时间复杂度为
O(log n)
的算法解决此问题。 -
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8 输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6 输出:[-1,-1]
示例 3:
输入:nums = [], target = 0 输出:[-1,-1]
-
vector<int> searchRange(vector<int>& nums, int target) { int left = 0,right = nums.size(); int mid = 0; while(left < right) { mid = left+ ((right - left)>>1); if( nums[mid] > target ) { right = mid; }else if(nums[mid] < target) { left = mid +1; }else{ break; } } if(left == right) return {-1,-1}; left = mid; right = mid; while(left-1 >= 0 && nums[left-1] == target) { left --; } while(right+1 < nums.size() && nums[right+1] == target) { right ++; } return {left,right}; }
-
先找到target, 再往两边扩展
-
vector<int> searchRange(vector<int>& nums, int target) { // vector<int> result; int left = 0; int right = nums.size(); int first = -1, last =-1 ; while(left < right) { int mid = left + ((right - left) >>1); if(nums[mid] > target) { right = mid; }else if(nums[mid] < target) { left = mid+1; }else{ right = mid; first = mid; } } left = 0; right = nums.size(); while(left < right) { int mid = left + ((right - left) >>1); if(nums[mid] > target) { right = mid; }else if(nums[mid] < target) { left = mid+1; }else{ left = mid + 1; last = mid; } } return {first,last}; }
-
找左边界的时候,将找到的第一个target 作为新的右边界
69. x 的平方根
-
给你一个非负整数
x
,计算并返回x
的 算术平方根 。由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
**注意:**不允许使用任何内置指数函数和算符,例如
pow(x, 0.5)
或者x ** 0.5
。 -
示例 1:
输入:x = 4 输出:2
示例 2:
输入:x = 8 输出:2 解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
-
int mySqrt(int x) { if(x == 0) return 0; if(x<=3) return 1; if(x<=8) return 2; long long left = 3,right = x/2; // /2 属于剪枝, 但是4特例 while( left < right ) { long long mid = left + ((right - left)>>1); if(mid * mid < x) // mid < x / mid; { left = mid +1; }else if( mid * mid > x ){ right = mid ; }else{ return mid; } } return left-1; //此时left = right ,但是right 无意义 // right是向上取整 }
-
二分的+1 -1 必须带着,要不然会陷入死循环
-
int mySqrt(int x) { if(x == 0) return 0; if(x<=3) return 1; if(x<=8) return 2; long long left = 3,right = x/2; while( left <= right ) { long long mid = left + ((right - left)>>1); if(mid * mid < x) { left = mid + 1; }else if( mid * mid > x ){ right = mid-1 ; }else{ return mid; } } return right; // 带等号的时候,退出时left > right }
-
牛顿迭代 : 快速求解函数零点的方法。
-
用 C 表示待求出平方根的那个整数 ,C 的平方根就是函数 y= x^2 - C 的零点
-
int mySqrt(int x) { if(x == 0) return 0; double C = x,x0= x; while(true) { double xi = 0.5*(x0 + C /x0); //切线与x轴交点 if(fabs(x0 - xi) < 1e-7) { break; } x0 = xi; } return int(x0); }
-
2 双指针
- 指针方向既可以同向,也可以相向而行
27. 移除元素
-
给你一个数组
nums
和一个值val
,你需要 原地 移除所有数值等于val
的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用
O(1)
额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
-
示例 1:
输入:nums = [3,2,2,3], val = 3 输出:2, nums = [2,2] 解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
示例 2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2 输出:5, nums = [0,1,3,0,4] 解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
-
int removeElement(vector<int>& nums, int val) { int i = 0,j =0; while(j < nums.size()) { if(nums[j] != val) { nums[i] = nums[j]; i++; } j++; } return i; }
26. 删除有序数组中的重复项
-
给你一个 非严格递增排列 的数组
nums
,请你** 原地** 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回nums
中唯一元素的个数。 -
示例 1:
输入:nums = [1,1,2] 输出:2, nums = [1,2,_] 解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
示例 2:
输入:nums = [0,0,1,1,1,2,2,3,3,4] 输出:5, nums = [0,1,2,3,4] 解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。
-
int removeDuplicates(vector<int>& nums) { if(nums.size() == 1) return 1; int i = 1,j = 1; while(j < nums.size()) { if( nums[j] != nums[i-1] ) { nums[i] = nums[j]; i++; } j++; } return i; }
-
只将第一次出现的数保存下来
844. 比较含退格的字符串
-
给定
s
和t
两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回true
。#
代表退格字符。**注意:**如果对空文本输入退格字符,文本继续为空。
-
示例 1:
输入:s = "ab#c", t = "ad#c" 输出:true 解释:s 和 t 都会变成 "ac"。
示例 2:
输入:s = "ab##", t = "c#d#" 输出:true 解释:s 和 t 都会变成 ""。
示例 3:
输入:s = "a#c", t = "b" 输出:false 解释:s 会变成 "c",但 t 仍然是 "b"。
-
bool backspaceCompare(string s, string t) { int i = 0,j =0; int sNum ,tNum ; while(j < s.size()) { if(s[j] != '#') { s[i] = s[j]; i++; }else if(i > 0){ i--; } j++; } sNum = i; i = 0,j = 0; while(j < t.size()) { if(t[j] != '#') { t[i] = t[j]; i++; }else if(i > 0){ i--; } j++; } tNum = i; if(sNum != tNum) return false; i = 0; while(i< sNum) { if(s[i] != t[i]) return false; i++; } return true; }
-
仿照前面两个题的思路,从左往右双指针遍历
-
匹配消除还可以用栈的思路
977. 有序数组的平方
-
给你一个按 非递减顺序 排序的整数数组
nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序 -
示例 1:
输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100] 排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11] 输出:[4,9,9,49,121]
-
//中间往两边取,费时费力 vector<int> sortedSquares(vector<int>& nums) { vector<int>result; int zeroIndex = 0; int left ,right; if(nums[0] >= 0 ) { for(int i =0;i< nums.size();i++) { result.push_back(nums[i]*nums[i]); } return result; }else if( nums[nums.size()-1] <= 0 ){ for(int i =nums.size()-1;i>=0;i--) { result.push_back(nums[i]*nums[i]); } return result; } for(int i =0;i< nums.size();i++) { if(nums[i]< 0 &&nums[i+1]>=0 ) { left = i,right = i+1; } } while(left >= 0 && right<= nums.size()-1) { if( fabs(nums[left]) > fabs(nums[right]) ) { result.push_back(nums[right]*nums[right]); right++; }else{ result.push_back(nums[left]*nums[left]); left--; } } while(left>=0) { result.push_back(nums[left]*nums[left]); left--; } while(right <= nums.size()-1) { result.push_back(nums[right]*nums[right]); right++; } return result; }
-
vector<int> sortedSquares(vector<int>& nums) { vector<int>result(nums.size(),0); int i = 0,j = nums.size()-1; int num = nums.size()-1; while(i<=j) { if(fabs(nums[i]) < fabs(nums[j])) { result[num] = nums[j] * nums[j]; j--; }else{ result[num] = nums[i] * nums[i]; i++; } num--; } return result; }
-
两边往中间遍历,不用判断0在哪