LeetCode学习记录(数组篇)

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
  • 遇到的问题
    1. 函数形参:遇到数组时传入首元素地址,所以需要定义指针类型形参
      在这里插入图片描述
    2. 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. 自己写代码

  • 思路:模拟顺时针画矩阵的过程

    填充上行从左到右
    填充右列从上到下
    填充下行从右到左
    填充左列从下到上

    由外向内一圈一圈这么画下去。

  • 图示:在这里插入图片描述

  • 注意:始终保持左闭右开一致!

  • 代码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
题目描述:给定一个非负整数数组nums和一个整数m,你需要将这个数组分成m个非空的连续子数组。设计一个算法使得这m个子数组中的最大和最小。 解题思路: 这是一个典型的二分搜索题目,可以使用二分查找来解决。 1. 首先确定二分的左右边界。左边界为数组中最大的值,右边界为数组中所有元素之和。 2. 在二分搜索的过程中,计算出分割数组的组数count,需要使用当前的中间值来进行判断。若当前的中间值不够分割成m个子数组,则说明mid值偏小,将左边界更新为mid+1;否则,说明mid值偏大,将右边界更新为mid。 3. 当左边界小于等于右边界时,循环终止,此时的左边界即为所求的结果。 具体步骤: 1. 遍历数组,找到数组中的最大值,并计算数组的总和。 2. 利用二分查找搜索左右边界,从左边界到右边界中间的值为mid。 3. 判断当前的mid值是否满足题目要求,若满足则更新右边界为mid-1; 4. 否则,更新左边界为mid+1。 5. 当左边界大于右边界时,循环终止,返回左边界即为所求的结果。 代码实现: ```python class Solution: def splitArray(self, nums: List[int], m: int) -> int: left = max(nums) right = sum(nums) while left <= right: mid = (left + right) // 2 count = 1 total = 0 for num in nums: total += num if total > mid: total = num count += 1 if count > m: left = mid + 1 else: right = mid - 1 return left ``` 时间复杂度分析:二分搜索的时间复杂度为O(logN),其中N为数组的总和,而遍历数组的时间复杂度为O(N),因此总的时间复杂度为O(NlogN)。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值