代码随想录算法训练营第1天 | 第一章 数组part01


今日记录


数组理论基础

知识记录:

  1. 存放在连续内存空间上的相同类型数据的集合。
  2. 数组下标都是从0开始的 —— 增减元素时要移动其余的元素地址。
  3. vector array的区别:vector的底层实现是array,严格来讲vector是容器,不是数组。
  4. 数组的元素是不能删的,只能覆盖。
  5. 二维数组也是连续分布的:先行后列存放地址。

704. 二分查找

Leetcode题目链接

题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

1.二分法查找理论记录

查找基础

有序数组且无重复元素

思路

定义left=0,right=numsize-1为左右边界索引,middle=(left+right)/2为中间值索引,比较target值与nums[middle]的值是否相等,根据二分搜索的思路更新每一次搜索的区间。

关键点

  1. while ( left < right ) or while ( left <= right )
  2. 更新区间左右边界时 right = middle or right = middle - 1 (left = middle or left = middle + 1)

两种情况讨论:

1. 左闭右闭 [left, right]

关键点1:此时若取”=“,[ left, right ] 区间合法( EX : [1, 1] ),所以取 while ( left <= right )
关键点2:判断条件为 if ( nums[middle] > target ),target一定无法取到nums[middle],结合左闭右闭区间的条件,所以 right = middle - 1 ( [ left, middle-1 ] )

2. 左闭右开 [left, right)

关键点1:此时若取”=“,[ left, right ) 区间合法( EX : [1, 1) ),所以取 while ( left < right )
关键点2:判断条件为 if ( nums[middle] > target ),target一定无法取到nums[middle],但此时是左闭右开区间,本来就无法取到右边界,所以 right = middle ( [ left, middle ) )

2.代码实现(以左闭右闭为例)

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int middle;
        while (left <= right) {
            middle = (left + right) / 2;
            if (nums[middle] > target) {
                right = middle - 1;
            } else if (nums[middle] < target) {
                left = middle + 1;
            } else
                return middle;
        }
        return -1;
    }
};

3.复杂度:

时间复杂度:时间复杂度的计算并不是计算程序具体运行的时间,而是算法执行语句的次数。
空间复杂度:空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度

对于二分法,假设共有n个元素,查找区间为 n/2, n/4, n/8,…,n/2^k,k为执行次数即为时间复杂度,k最大时区间最小为1,令
n/2^k=1,解出k=log2n (2为底n的对数)

27. 移除元素

LeetCode链接

题目:给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

双层for循环实现

时间复杂度:两个for循环为O(n^2)

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        for (int i = 0; i <= size - 1; i++) {
            if (nums[i] == val) {
                for (int j = i + 1; j <= size - 1; j++) {
                    nums[j - 1] = nums[j];
                }
                i--;
                size -= 1;
            }
        }
        return size;
    }
};

双指针思路

明确快慢指针到底指向的什么:

快指针(fast)代表的是新数组中的元素(本题中代表nums[fast] != val 的值);
慢指针(slow)代表的是新数组的下标(令num[slow] = nums[fast])

时间复杂度:单个for循环为O(n)

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int fast;
        int slow = 0;
        for (fast = 0; fast < nums.size(); fast++) {
            if (nums[fast] != val) {
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }
};

细节注意:fast < nums.size() 和 fast <= nums.size()-1 没什么区别,那为什么第二个会在空数组时报数组越界的错误?
vector的size()函数返回值是无符号整数,空数组时返回了0,再减个一会溢出

总结

今日学习时长2小时,彻底搞懂了

  • 16
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
第二十二天的算法训练主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值