1. 二分查找(简单)
题目描述:
给定一个
n
个元素有序的(升序)整型数组nums
和一个目标值target
,写一个函数搜索nums
中的target
,如果目标值存在返回下标,否则返回-1
。
二分查找思想
二分查找是一种常用的查找算法,适用于有序数组或有序列表。它的基本思想是将查找区间逐渐缩小为一半,直到找到目标元素或确定目标元素不存在。
具体实现思路如下:
- 确定查找区间的起始位置和结束位置,通常为数组或列表的首尾元素索引。
- 计算查找区间的中间位置 mid = (start + end) / 2。
- 比较中间位置的元素与目标元素的大小关系:
- 如果中间位置的元素等于目标元素,则找到目标元素,返回结果。
- 如果中间位置的元素大于目标元素,则目标元素可能在左半部分,将结束位置更新为 mid - 1,继续执行步骤 2。
- 如果中间位置的元素小于目标元素,则目标元素可能在右半部分,将起始位置更新为 mid + 1,继续执行步骤 2。
- 重复步骤 2 和步骤 3,直到找到目标元素或确定目标元素不存在。
二分查找的时间复杂度是 O(logN),其中 N 是查找区间的大小。由于每次查找都将查找区间缩小为一半,因此它的效率非常高。但前提是要求查找的数据结构是有序的
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;
int mid=0;
while(left<=right){
mid=(right+left)/2;
if(nums[mid]<target){
left=mid+1;
}else if(nums[mid]>target){
right=mid-1;
}else{
return mid;
}
}
return -1;
}
}
2. 移除元素(简单)
题目描述:
给你一个数组
nums
和一个值val
,你需要 原地 移除所有数值等于val
的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用
O(1)
额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
首先,数组元素在内存地址中存储是连续的。不能删除单个元素,只能进行覆盖。
所以本次我们采用快慢指针法,快的指针(right)负责判断数组元素是否等于目标值,慢的指针(solw)负责覆盖目标值。时间复杂度O(n),空间复杂度O(1).
class Solution {
public int removeElement(int[] nums, int val) {
int solw=0;
for(int right=0;right<nums.length;right++){
if(nums[right]!=val){
nums[solw]=nums[right];
solw++;
}
}
return solw;
}
}
3. 有序数组的平方(简单)
题目描述:
给你一个按 非递减顺序 排序的整数数组
nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
暴力排序法: 首先我们可以使用暴力排序的方式来解决这道题,先将数组内的元素进行平方,然后对数据进行排序。
class Solution {
public int[] sortedSquares(int[] nums) {
for(int i=0;i<nums.length;i++){
nums[i]=nums[i]*nums[i];
}
Arrays.sort(nums);
return nums;
}
}
双指针排序法 : 因为数组元素是非递减的有序数组,所以元素平方最大值一定是在数组两边,所以我们可以使用双指针法,在数组第一位(left)和最后一位(right)将数组平方后进行对比,如果 left大,则left向前进一位,如果right大,则right向后退一步。
class Solution {
public int[] sortedSquares(int[] nums) {
int left=0;
int right=nums.length-1;
int[] result=new int[nums.length];
int index=nums.length-1;
while(left<=right){
if(nums[left]*nums[left]>nums[right]*nums[right]){
result[index]=nums[left]*nums[left];
left++;
}else{
result[index]=nums[right]*nums[right];
right--;
}
index--;
}
return result;
}
}
4. 长度最小的子数组(中等)
题目描述 :
给定一个含有
n
个正整数的数组和一个正整数target
。找出该数组中满足其和
≥ target
的长度最小的 连续子数组[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回0
。
滑动窗口 : 滑动窗口就是不断的调节序列的起始位置和终止位置,从而达到想要的结果。
首先都是r是快指针,l是慢指针。当r走到一定程度时达到了某种条件,此时用一个数result将r和l之间的距离存储起来,然后此时l开始向前进一步,如果此时l和r没有达到条件,则r向前进,直到达到条件。然后再将此时的r与l之间的距离与result相比较。从而达到获取长度最小的子数组。
AK代码
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int l=0;
int sum=0;
int result=Integer.MAX_VALUE;
for(int r=0;r<nums.length;r++){
sum+=nums[r];
while(target<=sum){
result=Math.min(result,r-l+1);
sum -=nums[l];
l++;
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
在本次代码中有一些语句
Integer.MAX_VALUE表示int数据类型的最大取值数:2 147 483 647
Integer.MIN_VALUE表示int数据类型的最小取值数:-2 147 483 648
Integer.MAX_VALUE ? 0 : result;
(关系表达式) ? 表达式1 : 表达式2; //与上面的语句对应
而该代码则是 如果result不等于Integer.MAX_VALUE,则输出result
示例:
int x = 10;
int y = 5;
int z;
如果x大于y 则是true,将x赋值给z;
如果x不大于y 则是false,将y赋值给z;
z = (x > y) ? x : y;
5. 螺旋矩阵(中等)
题目描述:
给你一个正整数
n
,生成一个包含1
到n2
所有元素,且元素按顺时针顺序螺旋排列的n x n
正方形矩阵matrix
。
class Solution {
public int[][] generateMatrix(int n) {
int loop = 0; // 控制循环次数
int[][] res = new int[n][n];
int start = 0; // 每次循环的开始点(start, start)
int count = 1; // 定义填充数字
int i, j;
while (loop++ < n / 2) { // 判断边界后,loop从1开始
// 模拟上侧从左到右
for (j = start; j < n - loop; j++) {
res[start][j] = count++;
}
// 模拟右侧从上到下
for (i = start; i < n - loop; i++) {
res[i][j] = count++;
}
// 模拟下侧从右到左
for (; j >= loop; j--) {
res[i][j] = count++;
}
// 模拟左侧从下到上
for (; i >= loop; i--) {
res[i][j] = count++;
}
start++;
}
if (n % 2 == 1) {
res[start][start] = count;
}
return res;
}
}