一、前言
九日集训第三天。
二、题目
1)33. 搜索旋转排序数组
整数数组 n u m s nums nums 按升序排列,数组中的值 互不相同 。在传递给函数之前, n u m s nums nums 在预先未知的某个下标 k ( 0 < = k < n u m s . l e n g t h ) k(0 <= k < nums.length) k(0<=k<nums.length)上进行了 旋转,使数组变为 [ n u m s [ k ] , n u m s [ k + 1 ] , . . . , n u m s [ n − 1 ] , n u m s [ 0 ] , n u m s [ 1 ] , . . . , n u m s [ k − 1 ] ] [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] [nums[k],nums[k+1],...,nums[n−1],nums[0],nums[1],...,nums[k−1]](下标 从 0 0 0 开始 计数)。例如, [ 0 , 1 , 2 , 4 , 5 , 6 , 7 ] [0,1,2,4,5,6,7] [0,1,2,4,5,6,7] 在下标 3 3 3 处经旋转后可能变为 [ 4 , 5 , 6 , 7 , 0 , 1 , 2 ] [4,5,6,7,0,1,2] [4,5,6,7,0,1,2] 。给你 旋转后 的数组 n u m s nums nums 和一个整数 t a r g e t target target ,如果 n u m s nums nums 中存在这个目标值 t a r g e t target target ,则返回它的下标,否则返回 − 1 -1 −1 。
1.a)题目分析:
由于本题是返回的下标为旋转后的数组的下标,所以可以不考虑升序排列的数组,直接使用 f o r for for循环遍历数组,并与整数 t a r g e t target target 进行比较,从而得到结果。
1.b)代码:
class Solution {
public int search(int[] nums, int target) {
int n = nums.length;
for(int i= 0;i<n;i++){
if(nums[i]==target){
return i;
}
}
return -1;
}
}
2)81.搜索旋转排序数组 II
已知存在一个按非降序排列的整数数组 n u m s nums nums ,数组中的值不必互不相同。在传递给函数之前, n u m s nums nums 在预先未知的某个下标 k ( 0 < = k < n u m s . l e n g t h ) k(0 <= k < nums.length) k(0<=k<nums.length)上进行了 旋转 ,使数组变为 [ n u m s [ k ] , n u m s [ k + 1 ] , . . . , n u m s [ n − 1 ] , n u m s [ 0 ] , n u m s [ 1 ] , . . . , n u m s [ k − 1 ] ] [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] [nums[k],nums[k+1],...,nums[n−1],nums[0],nums[1],...,nums[k−1]](下标 从 0 0 0 开始 计数)。例如, [ 0 , 1 , 2 , 4 , 4 , 4 , 5 , 6 , 6 , 7 ] [0,1,2,4,4,4,5,6,6,7] [0,1,2,4,4,4,5,6,6,7] 在下标 5 5 5 处经旋转后可能变为 [ 4 , 5 , 6 , 6 , 7 , 0 , 1 , 2 , 4 , 4 ] [4,5,6,6,7,0,1,2,4,4] [4,5,6,6,7,0,1,2,4,4] 。给你 旋转后 的数组 n u m s nums nums 和一个整数 t a r g e t target target ,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 n u m s nums nums在这个目标值 t a r g e t target target ,则返回 t r u e true true ,否则返回 f a l s e false false 。
2.a)题目分析:
本题与上题类似,只是在返回值上有所变化。
2.b)代码:
class Solution {
public boolean search(int[] nums, int target) {
int n = nums.length;
for(int i= 0;i<n;i++){
if(nums[i]==target){
return true;
}
}
return false;
}
}
3)153. 寻找旋转排序数组中的最小值
已知一个长度为 n n n 的数组,预先按照升序排列,经由 1 1 1 到 n n n 次 旋转 后,得到输入数组。例如,原数组 n u m s = [ 0 , 1 , 2 , 4 , 5 , 6 , 7 ] nums = [0,1,2,4,5,6,7] nums=[0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 4 4 次,则可以得到 [ 4 , 5 , 6 , 7 , 0 , 1 , 2 ] [4,5,6,7,0,1,2] [4,5,6,7,0,1,2]。
若旋转 7 次,则可以得到 [ 0 , 1 , 2 , 4 , 5 , 6 , 7 ] [0,1,2,4,5,6,7] [0,1,2,4,5,6,7]
注意,数组 [ a [ 0 ] , a [ 1 ] , a [ 2 ] , . . . , a [ n − 1 ] ] [a[0], a[1], a[2], ..., a[n-1]] [a[0],a[1],a[2],...,a[n−1]] 旋转一次 的结果为数组 [ a [ n − 1 ] , a [ 0 ] , a [ 1 ] , a [ 2 ] , . . . , a [ n − 2 ] ] [a[n-1], a[0], a[1], a[2], ..., a[n-2]] [a[n−1],a[0],a[1],a[2],...,a[n−2]] 。给你一个元素值 互不相同 的数组 n u m s nums nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为O(log n)
的算法解决此问题。
3.a)题目分析:
本题需要设计出一个时间复杂度的算法,分治法的专题中的二分法,它的时间复杂度O(log n)
,所以我们这题就可以使用二分法来解决。
3.b)代码:
class Solution {
public int findMin(int[] nums) {
int low = 0;
int high = nums.length - 1;
while (low < high) {
int mid = low + (high - low) / 2;
if (nums[mid] < nums[high]) {
high = mid;
} else {
low = mid + 1;
}
}
return nums[low];
}
}
4)70. 爬楼梯
假设你正在爬楼梯。需要 n n n 阶你才能到达楼顶。每次你可以爬 1 1 1 或 2 2 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
4.a)题目分析:
本题为斐波那契数列的应用,可以将第 n n n层分成从第 n − 1 n-1 n−1层爬上来和 n − 2 n-2 n−2层爬上来,将两次相加即可。
4.b)代码:
class Solution {
int []a=new int [1000];
public int climbStairs(int n) {
a[0]=a[1]=1;
for(int i=2;i<n+1;i++){
a[i]=a[i-1]+a[i-2];
}
return a[n];
}
}
5)509. 斐波那契数
斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2)
,其中n > 1
给定 n n n,请计算 F ( n ) F(n) F(n) 。
5.a)题目分析:
斐波那契数列可以通过 F(n) = F(n - 1) + F(n - 2)
,其中 n > 1
,来表示出来。
5.b)代码:
class Solution {
public int fib(int n) {
int []a=new int [1000];
a[0]=0;
a[1]=1;
for(int i=2;i<n+1;i++){
a[i]=a[i-1]+a[i-2];
}
return a[n];
}
}
6)1137. 第 N 个泰波那契数
泰波那契序列 T n Tn Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1
, 且在n >= 0
的条件下Tn+3 = Tn + Tn+1 + Tn+2
给你整数 n n n,请返回第 n n n个泰波那契数 T n Tn Tn 的值。
6.a)题目分析:
泰波那契数是斐波那契数的进阶。
6.b)代码:
class Solution {
public int tribonacci(int n) {
int []a=new int [1000];
a[0]=0;
a[1]=1;
a[2]=1;
for(int i=3;i<n+1;i++){
a[i]=a[i-1]+a[i-2]+a[i-3];
}
return a[n];
}
}
7)2006. 差的绝对值为 K 的数对数目
给你一个整数数组 n u m s nums nums 和一个整数 k k k ,请你返回数对 ( i , j ) (i, j) (i,j) 的数目,满足 i < j i < j i<j 且
|nums[i] - nums[j]| == k
。
∣ x ∣ |x| ∣x∣ 的值定义为:
如果 x > = 0 x >= 0 x>=0 ,那么值为 x x x 。
如果 x < 0 x < 0 x<0 ,那么值为 − x -x −x 。
7.a)题目分析:
本题可以用两层循环,来搜索满足条件的 ( i , j ) (i, j) (i,j),并统计数对的数目。
7.b)代码:
class Solution {
public int countKDifference(int[] nums, int k) {
int n =nums.length;
int ans=0;
for(int i =0;i<n;i++){
for(int j =i+1;j<n;j++){
int s =nums[i]-nums[j];
if(s==k||s==-k){
ans++;
}
}
}
return ans;
}
}
8)LCP 01. 猜数字
小 A A A 和 小 B B B 在玩猜数字。小 B B B 每次从 1 , 2 , 3 1, 2, 3 1,2,3 中随机选择一个,小 A A A 每次也从 1 , 2 , 3 1, 2, 3 1,2,3 中选择一个猜。他们一共进行三次这个游戏,请返回 小 A A A 猜对了几次?输入的 g u e s s guess guess数组为 小 A A A 每次的猜测, a n s w e r answer answer数组为 小 B B B 每次的选择。 g u e s s guess guess和 a n s w e r answer answer的长度都等于 3 3 3。
8.a)题目分析:
本题可以通过同时枚举 g u e s s guess guess数组和 a n s w e r answer answer数组,并进行比较。即可解决问题。
8.b)代码:
class Solution {
public int game(int[] guess, int[] answer) {
int n = guess.length;
int cnt=0;
for(int i = 0;i<n;i++){
if(guess[i]==answer[i]){
cnt++;
}
}
return cnt;
}
}
9)LCP 06. 拿硬币
桌上有 n n n 堆力扣币,每堆的数量保存在数组 c o i n s coins coins 中。我们每次可以选择任意一堆,拿走其中的一枚或者两枚,求拿完所有力扣币的最少次数。
9.a)题目分析:
本题需要将硬币分成奇数和偶数来计算,如果是偶数,则拿走一堆硬币需要 n / 2 n/2 n/2从;如果是奇数,则需要 n / 2 + 1 n/2+1 n/2+1次。因为是除 2 2 2,所以可以用位运算来解决本题。
9.b)代码:
class Solution {
public int minCount(int[] coins) {
int count = 0;
for(int coin: coins){
//右移一位相当于除以2,和1按位与相当于除2取余
count += (coin >> 1) + (coin & 1);
}
return count;
}
}
10)剑指 Offer II 069. 山峰数组的顶部
符合下列属性的数组 arr 称为 山峰数组(山脉数组) :
a r r . l e n g t h > = 3 arr.length >= 3 arr.length>=3
存在 i ( 0 < i < a r r . l e n g t h − 1 ) i(0 < i < arr.length - 1) i(0<i<arr.length−1)使得:
a r r [ 0 ] < a r r [ 1 ] < . . . a r r [ i − 1 ] < a r r [ i ] arr[0] < arr[1] < ... arr[i-1] < arr[i] arr[0]<arr[1]<...arr[i−1]<arr[i]
a r r [ i ] > a r r [ i + 1 ] > . . . > a r r [ a r r . l e n g t h − 1 ] arr[i] > arr[i+1] > ... > arr[arr.length - 1] arr[i]>arr[i+1]>...>arr[arr.length−1]
给定由整数组成的山峰数组 a r r arr arr ,返回任何满足 a r r [ 0 ] < a r r [ 1 ] < . . . a r r [ i − 1 ] < a r r [ i ] > a r r [ i + 1 ] > . . . > a r r [ a r r . l e n g t h − 1 ] arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] arr[0]<arr[1]<...arr[i−1]<arr[i]>arr[i+1]>...>arr[arr.length−1]的下标 i i i ,即山峰顶部。
10.a)题目分析:
定义一个整型 m a x max max,遍历数组,将数组中的每一个数与 m a x max max比较,如果比 m a x max max大,则将 a r r [ i ] arr[i] arr[i]赋值给 m a x max max并将下标给 a n s ans ans。
10.b)代码:
class Solution {
public int peakIndexInMountainArray(int[] arr) {
int n =arr.length;
int ans =0;
int max=0;
for(int i =0;i<n;i++){
if(max<arr[i]){
max=arr[i];
ans=i;
}
}
return ans;
}
}
三、做题记录
四、今日总结
今日的题目有需要用动态规划来考虑问题的,动态规划需要找重复、找变化、找边界。