文章目录
代码随想录开源LeetCode题单:代码随想录
一、数组基础
- 概念:数组是存放在连续空间上的相同类型数据的集合。
- 数组中每个元素都有一个特定的位置编号(从0开始),称之为索引(Index)。
- 数组元素索引的最大值 = 数组长度 - 1
- 存储空间
Java语言的存储空间分为栈空间和堆空间,数据类型分为基本数据类型和引用数据类型两种,数组属于引用数据类型。
其中,基本数据类型在栈中直接存储对象的值;而引用数据类型在栈中存储的是对象的引用(内存地址),在对空间中通过引用找到对象的值。
二、LeetCode题目
1.LeetCode704
1.1 二分查找算法
二分查找(Binary Search)又叫做折半查找,适用于有序数组。
每次查找都将目标范围缩小至原来的一半。
注意事项:
二分法的关键在于查找范围的区间选取与循环条件的对应。
区间为[left, right]
时,left == right
的区间有意义,while循环判断条件为left <= right
。
区间为[left, right)
时,left == right
的区间无意义,while循环判断条件为left < right
。
下面展示闭区间[left, right]
的算法。
算法描述
- 初始化左右边界
low
和high
。 - 计算中间位置
mid
,检查数组下标为mid
的元素arr[mid]
是否等于目标值。- 如果相等,则返回
mid
. - 如果目标值小于
arr[mid]
,则将high
移动到mid+1
。 - 如果目标值大于
arr[mid]
,则将high
移动到mid-1
。
- 如果相等,则返回
- 重复上述步骤,直到
low > high
,此时查找失败。
时间复杂度:
-
平均时间复杂度:O(log n)
-
最坏时间复杂度:O(log n)
空间复杂度:O(1)
1.2 代码
class Solution {
public int search(int[] nums, int target) {
if(target < nums[0] || target > nums[nums.length - 1]){
return -1;
}
int left = 0;
int right = nums.length - 1;
while(left <= right){
int mid = left + (right - left) / 2; //防止溢出
if(nums[mid] == target){
return mid;
}
else if (nums[mid] < target){
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
}
2.LeetCode27
数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
而两层for循环寻找并元素并一次使用后面的元素覆盖时间复杂度过大,容易超时。
可以考虑使用两个指针(数组下标)分别记录待删元素的位置以及需要填补到待删元素位置的数组元素的值,即算法中常用的双指针法。
2.1 快慢指针
2.1.1 思路
定义一个快指针和一个慢指针,慢指针用于指向待删元素的位置,快指针用于寻找填补到待删位置的新元素。
- 首先令慢指针
slow
和快指针fast
的下标都为0
。 - 使用
for
循环,fast
从0
开始遍历整个数组(fast < nums.length
)。
在每次循环中:
若nums[fast] != val
,则快指针指向的元素需要保留,用nums[fast]
覆盖nums[slow]
,然后slow
后移一位。
若nums[fast] == val
,则该元素应被删除,此时不进行操作,fast
指针后移继续寻找不等于val
的值,slow
指针原地等待后续赋值。 - 当
fast
完成遍历后,slow
指向新数组下标最大值的后一位,即为新数组长度。
2.1.2 代码
class Solution {
public int removeElement(int[] nums, int val) {
// 快慢指针
int slow = 0;
for (int fast = 0; fast < nums.length; fast++) {
if (nums[fast] != val) {
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
}
2.2 相向指针
2.2.1 思路
本题的实质要求是将数组中值不为val
的元素(查明个数k
)放在数组前面的位置,通过输出来检验,只需将前k
个元素都覆盖为值不为val
的即可,不需要考虑后面,也不需要实现交换。
- 定义左右两个指针,令
left=0
,right=nums.length - 1
,后需使他们相向移动
right左移动到从右数值不为val的位置,用于覆盖左边等于val的元素。 - while循环遍历数组,条件为
left <= right
当nums[left] == val
时,left
需要被移除,将right
覆盖到left,然后right--
(表示已经使用了这个元素)。
当nums[left]!= val
时,left
指向的不需要被移除,直接将left
右移动一位(left++
),继续检查下一个元素。
每次left
移动后,都需要再检查right
所指向的值是否等于val
,需要将right
左移到从右数值不为val
的位置。 - 当
left > right
,循环结束,此时left
就是数组中不等于val
的元素的数量k
,直接返回left
。
2.2.2 代码
class Solution {
public int removeElement(int[] nums, int val) {
int left = 0;
int right = nums.length - 1;
//将right移到从右数第一个值不为val的位置
while(right >= 0 && nums[right] == val) right--;
while(left <= right){
if(nums[left] == val){
//将right位置的数覆盖到left位置(输出只看前n个不为val的数)
nums[left] = nums[right];
right--;
}
left++;
//继续在右侧寻找值不为val的位置
while(right >= 0 && nums[right] == val) right--;
}
return left;
}
}
3.LeetCode977
3.1 思路
双指针(相向指针)
题目描述nums
数组按非递减排序(有正有负),则从两侧到中间绝对值依次减小;
题目要求新数组存储nums
数组中元素的平方且非递减,则可从后向前存储从大到小的平方值,即使用两个指针在nums
数组从两侧向中间寻找,两指针错位时停止寻找。
3.2 代码
class Solution {
public int[] sortedSquares(int[] nums) {
int pre = 0;
int rear = nums.length - 1;
int[] result = new int[nums.length];
int index = nums.length - 1;
while(pre <= rear){ // 从两侧寻找绝对值较小的数进行平方,存入新数组
if(Math.abs(nums[pre]) < nums[rear]){
result[index] = nums[rear] * nums[rear];
index--;
rear--;
} else {
result[index] = nums[pre] * nums[pre];
index--;
pre++;
}
}
return result;
}