704.二分查找
1. 题目
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
- 这道题前提是数组为有序数组,同时题目还强调数组中无重复元素
2.自己写一遍代码
#include<stdio.h>
int erfen(int arr[], int target,int len)
{
int left = 0;
int right = len - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] < target)
{
left = mid + 1;
}
else if (arr[mid] > target)
{
right = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int target = 7;
int len = sizeof(arr) / sizeof(arr[0]);
int xiabiao = erfen(arr, target,len);
printf("该值的下标为:%d", xiabiao);
}
输出:该值的下标为:6
3. 出错过地方
mid计算在while循环内
4. 其他写法
27.移除元素
1. 题目
给你一个数组 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。
你不需要考虑数组中超出新长度后面的元素。
- 数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖
2. 自己写代码
a) 暴力解法
- 两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组
- 时间复杂度:O(n^2) 空间复杂度:O(1)
- 图示
```c
#include<stdio.h>
int yichu(int* arr, int val,int len)
{
for (int i = 0; i < len; i++)
{
if (arr[i] == val)
{
for (int j = i; j < len-1; j++)
{
arr[j] = arr[j+1];
}
len--;
i--;
}
}
return len;
}
int main()
{
int arr[] = { 1,3,2,4,3,3,4,3};
int val = 3;
int len = sizeof(arr) / sizeof(arr[0]);
int afterlen=yichu(arr, val,len);
printf("移除后数组为:\n");
for (int i = 0; i < afterlen; i++)
{
printf("%d ", arr[i]);
}
}
输出:移除后数组为:
1 2 4 4
- 遇到的问题
- 函数形参:遇到数组时传入首元素地址,所以需要定义指针类型形参
len--;i--;
删除一个元素时,需要后面覆盖前面元素,此时长度-1,但必须回退一步,即i--
,否则会错过一个元素
- 函数形参:遇到数组时传入首元素地址,所以需要定义指针类型形参
b) 双指针解法
- 双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
- 定义快慢指针
快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置 - 理解:快指针找到非移除值的时候,慢指针重新赋值为该值,指针往前一位,如果为移除值,快指针往前一位,而慢指针不变
- 时间复杂度O(n)
- 图示
//双指针
int yichu2(int* arr, int val, int len)
{
int slow = 0;
for (int fast = 0;fast < len; fast++)
{
if (arr[fast] != val)
{
arr[slow] = arr[fast];
slow++;
}
}
return slow;//慢指针指向的位置就是移除后数组个数
}
- 注意,最后返回的值是慢指针指向的位置,也就是移除后新数组个数。
3. 参考
977.有序数组的平方
1. 题目
给你一个按 非递减顺序 排序的整数数组 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]
2. 自己写代码
a) 暴力解法
- 直接循环数组,每个数平方,再使用快速排序排序
- 其中调用了
<stdlib.h>
库函数中快速排序函数qsort()
,详情见qsort函数用法 - 时间复杂度:O(n+nlogn)
```c
#include<stdio.h>
#include <stdlib.h>
int cmpfunc(const void* a, const void* b)
{
return (*(int*)a - *(int*)b);
}
void SqrtSort(int* arr,int len)
{
for (int i = 0; i < len; i++)
{
arr[i] *= arr[i];
}
qsort(arr, len, sizeof(arr),cmpfunc);
}
int main()
{
int arr[] = { -1,32,1,23,2,5 };
int len = sizeof(arr) / sizeof(arr[0]);
SqrtSort(arr,len);
for (int i = 0; i < len; i++)
printf("%d ", arr[i]);
return 0;
}
输出结果:1 1 4 25 529 1024
b) 双指针解法
- 思想:从两边到中间:两边元素平方后最大,中间元素最小。由小到大输出,则下标由大到小开始存
- 实现方法:左右指针分别指向数列头、尾,当左指针<=右指针时,比较指向的数的平方的大小,大的一个写入新的数组中(前后两个数组长度相同)
- 代码
int* SqrtSort2(int* arr, int len)
{
//最后要返回的结果数组
int* ans = (int*)malloc(sizeof(int)*len);
int k=len-1 ;//返回数组由后往前排列
for (int left = 0,right = len - 1;left<=right;)//left<=right 等号不能省略
{
if (arr[left] * arr[left] >= arr[right] * arr[right])
{
ans[k] = arr[left] * arr[left];
left ++;
k--;
}
else
{
ans[k] = arr[right] * arr[right];
right--;
k--;
}
}
return ans;//返回数组指针
}
int main()
{
int arr[] = { -122,1,2,3,32,53 };
int len = sizeof(arr) / sizeof(arr[0]);
int *ans=SqrtSort2(arr,len);
for (int i = 0; i < len; i++)
printf("%d ", ans[i]);
return 0;
}
输出:1 4 9 1024 2809 14884
- 注意:返回数组指针,且输入数组是有序的
- 代码2
```c
int* sortedSquares(int* nums, int numsSize, int* returnSize) {
//返回的数组大小就是原数组大小
*returnSize = numsSize;
//创建两个指针,right指向数组最后一位元素,left指向数组第一位元素
int right = numsSize - 1;
int left = 0;
//最后要返回的结果数组
int* ans = (int*)malloc(sizeof(int) * numsSize);
int index;
for (index = numsSize - 1; index >= 0; index--) {
//左指针指向元素的平方
int lSquare = nums[left] * nums[left];
//右指针指向元素的平方
int rSquare = nums[right] * nums[right];
//若左指针指向元素平方比右指针指向元素平方大,将左指针指向元素平方放入结果数组。左指针右移一位
if (lSquare > rSquare) {
ans[index] = lSquare;
left++;
}
//若右指针指向元素平方比左指针指向元素平方大,将右指针指向元素平方放入结果数组。右指针左移一位
else {
ans[index] = rSquare;
right--;
}
}
//返回结果数组
return ans;
}
3. 参考
209 长度最小的子数组
1. 题目
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
提示:
1 <= target <= 10^9
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^5
2. 自己写代码
59.螺旋矩阵II
1. 题目
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3
输出:
[
[ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ]
]
2. 自己写代码
-
思路:模拟顺时针画矩阵的过程
填充上行从左到右
填充右列从上到下
填充下行从右到左
填充左列从下到上由外向内一圈一圈这么画下去。
-
图示:
-
注意:始终保持左闭右开一致!
-
代码