代码随想录算法训练营第一天_704.二分查找、27.移除元素、977.有序数组的平方
第一章 数组part01
数组理论基础
知识点:
- 数组是存放在连续内存空间上的相同类型数据的集合
- 数组的下标从0开始
- 数组内存空间的地址是连续的,不能单独删除数组中的某个元素,只能覆盖
- 内存地址怎么看:0x7ffee4065820与0x7ffee4065824 差了4,就是差了4个字节。因为这是一个int类型数组,所以相邻数组元素地址差4个字节。
#include <stdio.h>
void main(void)
{
int a[2][3] = {{0,1,2},{3,4,5}};
printf("%p %p %p \n%p %p %p"
,&a[0][0],&a[0][1],&a[0][2]
,&a[1][0],&a[1][1],&a[1][2]);
}
0x7fffffffdba0 0x7fffffffdba4 0x7fffffffdba8
0x7fffffffdbac 0x7fffffffdbb0 0x7fffffffdbb4[1] + Done "/usr/bin/gdb" --interpreter=mi --tty=${DbgTerm} 0<"/tmp/Microsoft-MIEngine-In-s5ppzjrh.xmq" 1>"/tmp/Microsoft-MIEngine-Out-ljflv5n3.ue1"
704.二分查找
**思路:**两种写法:1. 左闭右闭 2. 左闭右开
**关键词:**区间定义、左区间、右边界
易错点:
- 是while(left<=right)还是while(left<right)【思路:根据区间定义判断是不是合法区间?】
- if(nums[middle]>target)时 是right=middle还是right=middle-1 【思路:判断nums[middle]是否存在于区间内,重新定义边界后是否仍是合法区间】
**总结:**边界处理规则严格按照区间定义来写,[left, right]→[left, right] [left, right]
**ps:**两个int相加可能出现越界
答案:
-
左闭右开
int search(int* nums, int numsSize, int target) { int middle = 0; int left = 0; int right = numsSize; while(left < right){ middle = (left + right) / 2; if(nums[middle] > target){ right = middle;//[left right] -> [left1 right1) nums[middle] [left2 right2) } else if(nums[middle] < target){ left = middle + 1; } else return middle; } return -1; }
-
左闭右闭
int search(int* nums, int numsSize, int target) { int left = 0; int right = numsSize -1; int middle = 0; while(left<=right) { middle = (left + right)/2; if(target > nums[middle]) { left = middle + 1; } else if(target < nums[middle]) { right = middle -1; } else return middle; } return -1; }
27.移除元素
知识点:
思路:暴力解法O(n^2) O(1)【两个for循环】,快慢指针O(n) O(1)
总结:先把绝对会有的代码先写上去,确保一定准确,不确保就把所有可能性列出来。
答案:
-
暴力解法
int removeElement(int* nums, int numsSize, int val) { for(int i = 0; i<numsSize;i++){ if(nums[i] == val){ for(int j = i; j<numsSize-1;j++){ nums[j] = nums[j + 1];//易错点:不能使用自增 } numsSize--; i--;//易错点:当你在内层循环中移动元素后,你并没有更新外层循环的索引 i。这意味着如果你移除了一个元素,那么下一个元素(即原来的 nums[i+1] 现在变成了 nums[i])将被跳过而不会被检查。 } } return numsSize; }
-
快慢指针
int removeElement(int* nums, int numsSize, int val) { int idx_slow = 0; for(int idx_quick = 0; idx_quick < numsSize; idx_quick++){ if(nums[idx_quick] != val){ nums[idx_slow] = nums[idx_quick]; idx_slow++; } } return idx_slow; } //要有两个数组的意识
ps:补充数据结构关于时间复杂度与空间复杂度的知识
977.有序数组的平方
答案:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* sortedSquares(int* nums, int numsSize, int* returnSize) {
*returnSize = numsSize;
int left_idx=0;
int right_idx=numsSize-1;
int* square_array = (int*)malloc(sizeof(int) * numsSize);
for(int i = numsSize -1;i>-1;i--){
if(nums[left_idx] * nums[left_idx] > nums[right_idx] * nums[right_idx]){
square_array[i] = nums[left_idx] * nums[left_idx];
left_idx++;
}
else{
square_array[i] = nums[right_idx] * nums[right_idx];
right_idx--;
}
}
return square_array;
}
//学会读题,返回值要确定好,限制条件要确定好
今日任务
数组理论基础,704. 二分查找,27. 移除元素
详细布置
数组理论基础
文章链接:https://programmercarl.com/%E6%95%B0%E7%BB%84%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
题目建议: 了解一下数组基础,以及数组的内存空间地址,数组也没那么简单。
704. 二分查找
题目建议: 大家今天能把 704.二分查找 彻底掌握就可以,至于 35.搜索插入位置 和 34. 在排序数组中查找元素的第一个和最后一个位置 ,如果有时间就去看一下,没时间可以先不看,二刷的时候在看。
先把 704写熟练,要熟悉 根据 左闭右开,左闭右闭 两种区间规则 写出来的二分法。
题目链接:https://leetcode.cn/problems/binary-search/
文章讲解:https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html
视频讲解:https://www.bilibili.com/video/BV1fA4y1o715
27. 移除元素
题目建议: 暴力的解法,可以锻炼一下我们的代码实现能力,建议先把暴力写法写一遍。 双指针法 是本题的精髓,今日需要掌握,至于拓展题目可以先不看。
题目链接:https://leetcode.cn/problems/remove-element/
文章讲解:https://programmercarl.com/0027.%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.html
视频讲解:https://www.bilibili.com/video/BV12A4y1Z7LP
977.有序数组的平方
题目建议: 本题关键在于理解双指针思想
题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/
文章讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html
视频讲解: https://www.bilibili.com/video/BV1QB4y1D7ep