二分法
在排序数组中查找元素的第一个和最后一个位置:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/
搜索插入位置:https://leetcode.cn/problems/search-insert-position/
x 的平方根:https://leetcode.cn/problems/sqrtx/
完全的有效平方数:https://leetcode.cn/problems/valid-perfect-square/
答案
// 34题
int binarySearch(int* nums, int numsSize, int target, bool lower) {
int left = 0, right = numsSize - 1, ans = numsSize;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] > target || (lower && nums[mid] >= target)) {
right = mid - 1;
ans = mid;
} else {
left = mid + 1;
}
}
return ans;
}
int* searchRange(int* nums, int numsSize, int target, int* returnSize) {
int leftIdx = binarySearch(nums, numsSize, target, true);
int rightIdx = binarySearch(nums, numsSize, target, false) - 1;
int* ret = malloc(sizeof(int) * 2);
*returnSize = 2;
if (leftIdx <= rightIdx && rightIdx < numsSize && nums[leftIdx] == target && nums[rightIdx] == target) {
ret[0] = leftIdx, ret[1] = rightIdx;
return ret;
}
ret[0] = -1, ret[1] = -1;
return ret;
}
// 35题
// 二叉搜索查找目标值索引(优先返回靠前的索引)
int binarySearch(int* nums, int left, int right,int target){
int index;
while(left <= right){
int mid = (left+right)/2;
if(nums[mid] > target){
right = mid-1;
index = mid;
}
else if(nums[mid] < target){
left = mid+1;
}
else
return mid;
}
return index;
}
int searchInsert(int* nums, int numsSize, int target){
if(nums[numsSize-1] < target) //由于优先找靠前的,因此这种情况会出错
return numsSize;
int index = binarySearch(nums, 0, numsSize-1, target);
if(nums[index] < target)
return index+1;
else
return index;
}
// 69题
int mySqrt(int x){
int max = x;
int min = 0;
int t = 1;
if(x == 1)
return 1;
// 此处判断意味着区间缩小为1
while(max - min > 1){
t = (max + min)/2;
// 缩小区间
if(x/t < t)
max = t;
else
min = t;
}
return min;
}
补充
对于第69题,可以用牛顿二分法做
牛顿二分法:
x n + 1 = x n − f ( x n ) f ′ ( x n ) x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)} xn+1=xn−f′(xn)f(xn)
令
f
(
x
)
=
x
2
−
n
=
0
f(x) = x^2 - n = 0
f(x)=x2−n=0 // 其中n是结果
则 x n + 1 = x n − x n 2 − n 2 x n x_{n+1} = x_n - \frac{{x_n}^2 - n}{2x_n} xn+1=xn−2xnxn2−n
= 1 2 ( x n + n x n ) = \frac{1}{2}(x_n + \frac{n}{x_n}) =21(xn+xnn)
即 int y = (x + n/x)/2
迭代到y*y <= x <= (y+1)*(y+1)
为止,
代码如下:
int mySqrt(int x){
if(x == 0)
return 0;
int n = x;
// 防止整数溢出
int y = (n - x/n ) / 2 + x/n;
do{
n = y;
y = (n + x / n) / 2;
}while(x/n < n);
return n;
}
// 367题
bool isPerfectSquare(int num){
int n = num;
// 防止整数溢出
int y = (n - num/n ) / 2 + num/n;
do{
n = y;
y = (n + num / n) / 2;
}while(num/n < n);
if(n*n == num)
return true;
else
return false;
}
移除元素
删除有序数组中的重复项:https://leetcode.cn/problems/remove-duplicates-from-sorted-array/
移动零:https://leetcode.cn/problems/move-zeroes/
比较含退格的字符串:https://leetcode.cn/problems/backspace-string-compare/
这个题特别注意,
它磨灭了我今天刷题的激情提示:从后往前遍历,先消除,后比较
答案
// 26题
int removeDuplicates(int* nums, int numsSize){
if(numsSize == 1)
return 1;
//从后往前覆盖-双指针
int length = 0;
int i = 0,j = 1;
while(j+1 <= numsSize){
if(nums[i] != nums[j]){
nums[++i] = nums[j];
}
j++;
}
length = ++i;
return length;
}
// 283题
void moveZeroes(int* nums, int numsSize){
int j = 0;
for(int i = 0; i < numsSize; i++)
if(nums[i] != 0)
nums[j++] = nums[i];
for( ;j < numsSize; j++)
nums[j] = 0;
}
// 844题
bool backspaceCompare(char * s, char * t){
int i = strlen(s)-1;
int j = strlen(t)-1;
int sBack = 0;
int tBack = 0;
while(1){
while(i >= 0){
if(s[i] == '#')
sBack++;
else{
if(sBack > 0)
sBack--;
else
break;
}
i--;
}
while(j >= 0){
if(t[j] == '#')
tBack++;
else{
if(tBack > 0)
tBack--;
else
break;
}
j--;
}
// #已消完,比较s[i]和t[j]
if(i < 0 || j < 0)
break;
if(s[i] != t[j])
return false;
i--, j--;
}// while(1)
if(i == -1 && j == -1)
return true;
return false;
}
长度最小的子数组
- 水果成篮:https://leetcode.cn/problems/fruit-into-baskets/
答案
// 904题 暴力解(会超时
int totalFruit(int* fruits, int fruitsSize){
int fruitA = fruits[0];
int fruitB = fruits[0];
int total = 0;
int result = 0;
int flag = 0;
int i, j;
for(i = 0; i < fruitsSize; i++){
fruitA = fruits[i];
for(j = i; j < fruitsSize; j++){
// 给fruitB赋值
if(fruits[j] != fruitA && flag == 0){
fruitB = fruits[j];
flag = 1;
}
// total自增
if(fruits[j] == fruitA || fruits[j] == fruitB){
total++;
}
else
break;
}
// 更新result
if(result < total){
result = total;
}
total = 0;
flag = 0;
}
return result;
}
//904题 滑动窗口法
int totalFruit(int* fruits, int fruitsSize){
int fruitA = fruits[0];
int fruitB = fruits[0];
int total = 0;
int i = 0, j = 0;
while(j < fruitsSize){
if(fruits[j] == fruitA || fruits[j] == fruitB){
// 滑动窗口长度的计算!!!
total = (total > j-i+1) ? total : j-i+1;
j++;
}
else{// 若出现第三种水果
i = j - 1; // 更新滑动窗口左端i
fruitA = fruits[i]; // 更新水果A
while(i >= 1 && fruits[i-1] == fruitA) //更新i到理想位置
i--;
fruitB = fruits[j]; // 更新水果B
total = (total > j-i+1) ? total : j-i+1;
}
}
return total;
}
/*
要抓住循环过程中的变量与不变量
本题当水果类型固定后,fruitA与fruitB就是不变量,而滑动窗口边界i与j还能变化*/
螺旋数组
剑指offer29:https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/
- 螺旋矩阵:https://leetcode.cn/problems/spiral-matrix/
这两个题一样
这个题没答案是因为我放弃了,还有一道困难题
也放弃了
- 最小覆盖子串:https://leetcode.cn/problems/minimum-window-substring/
本题隶属于
长度最小的子数组
,那一道题需满足一个条件,推荐的题(水果篮)需要满足两个条件,本题需要满足m个条件。
本文只是节选公众号的中的一篇,我的公众号每日都会更新,欢迎参观
公众号算法每日一更