系列:数组专练
语言:java & go
题目来源:Leetcode
常考点: 二分 & 双指针 & 滑动窗口 & 模拟行为
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
经典的二分模板类型题,对于已经排序好的数组,要找某一个数,直接要想到可以使用二分法来进行解决。时间复杂度O(logn)
java参考代码:
class Solution {
public int search(int[] nums, int target) {
if(target<nums[0] || target>nums[nums.length-1]){
return -1;
}
int left = 0,right =nums.length-1;
while(left<=right){
int mid = left +((right-left)>>1);
if(nums[mid] == target){
return mid;
}
if(nums[mid]>target){
right =mid-1;
}
if(nums[mid]<target){
left = mid+1;
}
}
return -1;
}
}
go参考代码:
func search(nums []int, target int) int {
if target<nums[0] || target>nums[len(nums)-1]{
return -1;
}
left,right := 0,len(nums)-1
for left<=right{
mid := left+((right-left)>>1)
if nums[mid] == target{
return mid
}
if nums[mid]<target{
left =mid+1
}
if nums[mid]>target{
right =mid-1
}
}
return -1
}
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
这道题要求使用O(logn),同时也是排序后的数组,所以可以使用二分法来进行排序
java参考代码:
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0,right=nums.length-1;
while(left<=right){
int mid = left+((right-left)>>1);
if(nums[mid] == target){
return mid;
}else if(nums[mid]<target){
left=mid+1;
}else{
right = mid-1;
}
}
return left;
}
}
go参考代码:
func searchInsert(nums []int, target int) int {
left,right :=0,len(nums)-1
for left<= right{
mid:=left+((right-left)>>1)
if nums[mid] == target {
return mid
}
if nums[mid] > target {
right = mid-1
}
if nums[mid] < target {
left = mid+1
}
}
return left
}
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
题中对时间复杂度进行了要求,同时题中要求了数组为非递减,所以可以使用二分法。但是这道题返回的是一个范围,我们知道,二分法每次只能确定一个值,所以我们可以通过两次二分,来分别获得左边界和右边界的值,最后返回一个区间。
本文之前有过讲解,具体思路和流程参考这里:Leetcode34思路解读
java参考代码:
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = searchLeft(nums,target);
int right= searchright(nums,target);
if(left == -1 || right == -1){
return new int[]{-1,-1};
}else{
return new int[]{left,right};
}
}
//寻找目标值左边界m
public int searchLeft(int[]nums,int target){
int left=0,right=nums.length-1;
while(left<=right){
int mid =left+((right-left)>>1);
if(nums[mid] == target){
if(mid == 0 || nums[mid-1]<target){
return mid;
}
right =mid-1;
}
if(nums[mid]>target){
right = mid-1;
}
if(nums[mid]<target){
left = mid+1;
}
}
return -1;
}
public int searchright(int []nums,int target){
int left = 0,right=nums.length-1;
while(left<=right){
int mid = left+((right-left)>>1);
if(nums[mid] == target){
if(mid == nums.length-1 || nums[mid+1]>target){
return mid;
}
left = mid+1;
}
if(nums[mid]>target){
right=mid-1;
}
if(nums[mid]<target){
left = mid+1;
}
}
return -1;
}
}
go参考代码:
func searchRange(nums []int, target int) []int {
left := searchleft(nums,target)
right := searchright(nums,target)
if left== -1 || right == -1{
return []int{-1,-1}
}else{
return []int{left,right}
}
}
func searchleft(nums [] int,target int) int{
left,right:=0,len(nums)-1
for left<=right{
mid := left+((right-left)>>1)
if nums[mid] == target{
if mid == 0 || nums[mid-1]<target{
return mid
}
right = mid-1
}
if nums[mid]<target{
left =mid+1
}
if nums[mid]>target{
right = mid-1
}
}
return -1
}
func searchright(nums [] int,target int) int{
left,right:=0,len(nums)-1
for left<=right{
mid := left+((right-left)>>1)
if nums[mid] == target{
if mid == len(nums)-1 || nums[mid+1]>target{
return mid
}
left = mid+1
}
if nums[mid]<target{
left =mid+1
}
if nums[mid]>target{
right = mid-1
}
}
return -1
}
通过上面两道题的解题思路,你应该能有很多收获,下面这里两道题就当做课后练习吧,不会的话可以回顾前面题解思路,尝试自己去把做出来
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。
不能使用任何内置的库函数,如 sqrt 。
双指针法:通过一个快指针和慢指针在一个for循环下完成两个for循环的工作
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
本题主要考点是双指针中的快慢指针的应用,相信通过1,2,3题,你会有很多收获。本题之前有过讲解:可以参考该文献:移除元素思路讲解
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。
将最终结果插入 nums 的前 k 个位置后返回 k 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
本题的话,也是双指针的一个应用,快慢指针,本文之前有过讲解:可供参考思路:删除有效数组的重复项思路讲解
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
本题同样是双指针中快慢指针的练习,你可以尝试不看题解,自己做出来,就当做前两道题的练习题,考验一下自己的知识的了解程度
本文之前有过讲解:可以参考文章思路:移动零思路讲解
给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。
注意:如果对空文本输入退格字符,文本继续为空。
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
可以先思考,没有思路和头绪的话可以参考我之前的文章:长度最小的子数组思路解读
下面给出两道类似的滑动窗口练习题:做题首先想思路,没有思路的话可以参考题解
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
你只有 两个 篮子,并且每个篮子只能装 单一类型 的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从 每棵 树(包括开始采摘的树)上 恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的 最大 数目。
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
可以先思考,同时可以参考我之前文献思路:螺旋数组思路解读
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例 1:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1
输出:[[1]]
可以先思考,同时可以参考我之前的文献:螺旋数组II思路解读
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
go参考代码:
func spiralOrder(matrix [][]int) []int {
if(len(matrix) == 0){
return []int{}
}
top,left,right,bottom :=0,0,len(matrix[0])-1,len(matrix)-1
res :=[]int{}
for left<=right && top <=bottom{
for i:=left;i<=right;i++{res=append(res,matrix[top][i])}
top++
if top>bottom{
return res
}
for i:=top;i<=bottom;i++{res=append(res,matrix[i][right])}
right--
if right<left{
return res
}
for i:=right;i>=left;i--{res=append(res,matrix[bottom][i])}
bottom--
if bottom<top{
return res
}
for i:=bottom;i>=top;i--{res=append(res,matrix[i][left])}
left++
if left>right{
return res
}
}
return res
}