入门级
1.螺旋矩阵
描述:
给定一个m x n大小的矩阵(m行,n列),按螺旋的顺序返回矩阵中的所有元素
数据范围:
0≤n,m≤10,矩阵中任意元素都满足 |val| ≤100
要求:空间复杂度 O(nm)O(nm) ,时间复杂度 O(nm)O(nm)
实例:
输入:[[1,2,3],[4,5,6],[7,8,9]]
返回:[1,2,3,6,9,8,7,4,5]
输入:[]
返回:[]
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> spiralOrder(int[][] matrix) {
ArrayList<Integer> res = new ArrayList<>();
if(matrix.length == 0) return res;
int count = 0, row = matrix.length, column = matrix[0].length;
int total = row * column;
int up = 0, down = row - 1, left = 0, right = column - 1;
while(count < total){
for(int i = left; i <= right && count < total; i++){
res.add(matrix[up][i]);
count++;
}
up++;
for(int i = up; i <= down && count < total; i++){
res.add(matrix[i][right]);
count++;
}
right--;
for(int i = right; i >= left && count < total; i--){
res.add(matrix[down][i]);
count++;
}
down--;
for(int i = down; i >= up && count < total; i--){
res.add(matrix[i][left]);
count++;
}
left++;
}
return res;
}
}
2.斐波拉契数列
描述:大家都知道斐波那契数列,现在要求输入一个正整数 n ,请你输出斐波那契数列的第 n 项。
斐波那契数列是一个满足
的数列.
数据范围:1≤n≤40
要求:空间复杂度 O(1),时间复杂度 O(n) ,本题也有时间复杂度 O(logn) 的解法
实例:
输入:4
返回:3
输入:1
返回:1
//递归算法
public class Solution {
public int Fibonacci(int n) {
if(n==1||n==2) return 1;
return Fibonacci(n-1)+Fibonacci(n-2);
}
}
//最优算法
public class Solution {
public int Fibonacci(int n) {
int a=1,b=1,c=0;
for(int i=1;i<=n;i++){
a=b;
b=c;
c=a+b;
}
return c;
}
}
3.反转字符串
描述:写出一个程序,接受一个字符串,然后输出改字符串反转后的字符串(长度不超过1000)
数据范围:0≤n≤1000
要求:空间复杂度O(n),时间复杂度O(n)
实例1:
输入:"abcd"
返回值:"dcba"
实例2:
输入:""
返回值:""
//函数方式
public class Solution {
public String solve (String str) {
return new StringBuffer(str).reverse().toString();
}
}
//单链表方式
public class Solution {
public String solve (String str) {
char[] chars=str.toCharArray();
for(int i=str.length()-1;i>=0;i--)
chars[str.length()-i-1]=str.charAt(i);
return new String(chars);
}
}
//双链表方式
public class Solution {
public String solve (String str) {
char[] chars=str.toCharArray();
int left=0;
int right=str.length()-1;
while(left<right){
char temp=chars[left];
chars[left]=chars[right];
chars[right]=temp;
left++;
right--;
}
return new String(chars);
}
}
4.判断是否为回文字符串
描述:
给定一个长度为n的字符串,请编写一个函数判断改字符串是否回文.如果是回文请返回true,否则返回false.字符串回文指该字符串正序与其逆序逐字符一致.
数据范围:0<n<1000000
要求:空间复杂度O(1),时间复杂度O(n)
实例1:
输入:"absba"
返回值:true
实例2:
输入:"ranko"
返回值:false
//双链表判断
public class Solution {
public boolean judge (String str) {
char[] chars=str.toCharArray();
int left=0;
int right=str.length()-1;
while(left<right){
if(chars[left]!=chars[right]) return false;
left++;
right--;
}
return true;
}
}
5.最大公约数
描述:如果有一个自然数a能被自然数b整除,则称a为b的倍数,b为a的约数.几个自然数公有的约数,叫做这几个自然数的公约数.公约数中最大的一个公约数,称为这几个自然数的最大公约数.
输入a和b,请返回a和b的最大公约数
数据范围:1≤a,b≤10^9
进阶:空间复杂度O(1),时间复杂度O(logn)
实例1:
输入: 3,6
返回值:3
输入:8,12
返回值:4
//辗转相除法
public class Solution {
public int gcd (int a, int b) {
int min=(a<b)?a:b;
int max=0;
for(int i=min;i>0;i--){
if(a%i==0&&b%i==0){
max=i;
break;
}
}
return max;
}
}
简单级
1.链表中环的入口结点
描述:给一个长度为n的链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null.
数据范围:n≤10000,1≤结点值≤10000
要求:空间复杂度O(1),时间复杂度O(n)
例如,输入{1,2},{3,4,5}时,对应的环形链表如下图所示:
可以看到环的入口结点的结点值为3,所以返回结点值为3的结点.
输入描述:
输入分为2段,第一段是入环钱的链表部分,第二段是链表环的部分,后台会根据第二段是否为空将这两段组装成一个无环或者有环单链表
返回值描述:
返回链表的环的入口结点即可,我们后台程序会打印这个结点对应的结点值,若没有,则返回对应编程语言的空结点即可.
实例1:
输入:{1,2},{3,4,5}
返回值:3
实例2:
输入:{1},{}
返回值:"null"
实例3:
输入:{},{2}
返回值:2
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
//出现({},{})和({number},{})则返回null
if(pHead == null || pHead.next == null){
return null;
}
ListNode fast = pHead;
ListNode slow = pHead;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){ //快链表和慢链表重合时表示可以构成环
ListNode slow2 = pHead; //入口结点
while(slow2 != slow){
slow2 = slow2.next;
slow = slow.next;
}
return slow2;
}
}
return null;
}
}
2.判断链表中是否有环
判断给定的链表中是否有环,如果有环则返回true,否则返回false
数据范围:链表长度0≤n≤10000,链表中任意节点的值满足|val|<=1000000
要求:空间复杂度O(1),时间复杂度O(n)
输入分为两部分,第一部分为链表,第二部分代表是否有环,然后将组成的head头结点传入到函数里面.-1代表无环,其它的数字代表有环,这些参数解释仅仅是为了方便读者自测调试.实际在编程时读入的是链表的头结点.
例如输入{3,2,0,-4},1时,对应的链表结构如下图所示:
可以看出环的入口结点为从头结点开始的第1个结点(注:头结点为第0个结点),所以输出true.
实例1:
输入:{3,2,0,-4},1
返回值:true
实例2:
输入:{1},-1
返回值:false
实例3:
输入:{-1,-7,7,-4,19,6,-9,-5,-2,-5},6
返回值:true
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode fast=head;
ListNode slow=head;
while(fast != null && fast.next !=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow) return true;
}
return false;
}
}
3.买卖股票的最好时机
描述:假设你有一个数组prices,长度为n,其中prices[i]是股票在第i天的价格,请根据这个价格数组,返回买卖股票能获得的最大收益
1.你可以买入一次股票和卖出一次股票,并非每天都可以买入或卖出一次,总共只能买入和卖出一次,且买入必须在卖出的前面的某一天.
2.如果不能获取到任何利润,请返回0
3.假设买入卖出均无手续费
数据范围:0≤n≤10000,0≤val≤10000
要求:空间复杂度O(1),时间复杂度O(n)
实例1:
输入:[8,9,2,5,4,7,1]
返回值:5
实例2:
输入:[2,4,1]
返回值:2
实例3:
输入:[3,2,1]
返回值:0
//贪心算法
public class Solution {
public int maxProfit (int[] prices) {
//Integer.MAX_VALUE表示int数据类型的最大取值数:2 147 483 647
int minPrices=Integer.MAX_VALUE;
int P=0;
for(int i=0;i<prices.length;i++){
if(prices[i]<minPrices){
minPrices=prices[i];
}else if(prices[i]-minPrices>P){
P=prices[i]-minPrices;
}
}
return P;
}
}
4.二叉树中和为某一值的路径
描述:给定一个二叉树root和一个值sum,判断是否有从根节点到叶子节点的节点值之和等于sum'的路径.
1.该题路径定义为从树的根节点开始往下一直到叶子节点所经过的节点
2.叶子节点是指没有子节点的节点
3.路径只能从父节点到子节点,不能从子节点到父节点
4.总节点数目为n
例:
给出如下的二叉树,sum=22
返回true,因为存在一条路径5->4->11->2的节点值之和为22
数据范围:
1.树上的节点树满足0≤n≤10000
2.每个节点的值都满足|val|≤1000
要求:空间复杂度O(n),时间复杂度O(n)
进阶:空间复杂度O(树的高度),时间复杂度O(n)
实例1:
输入:{5,4,8,1,11,#,9,#,#,2,7},22
返回值:true
实例2:
输入:{1,2},3
返回值:false
实例3:{},0
返回值:false
//递归方法
public class Solution {
public boolean hasPathSum (TreeNode root, int sum) {
//根节点和叶子节点都为空时,无法遍历,返回null
if(root==null){
return false;
}
//从根节点一直向下减,减到最后一个节点得到为0时,返回true
if(root.left==null && root.right==null && sum-root.val==0){
return true;
}
//从左右节点分别向下减,只要其中一个能返回true即可
return hasPathSum(root.left,sum-root.val)||hasPathSum(root.right,sum-root.val);
}
}
5.将升序数组转化为平衡二叉搜索树
描述:给定一个升序排序的数组,将其转化为平衡二叉搜索树(BST)
平衡二叉搜索树指树上每个节点node都满足左子树中所有节点的值都小于node的值,右子树中所有节点的值都大于node的值,并且左右子树的节点数量之差不大于1
数据范围:0≤n≤10000,数组中每个值满足|val|≤5000
进阶:空间复杂度O(n),时间复杂度O(n)
例如当输入的升序数组为[-1,0,1,2]时,转化后的平衡二叉搜索树(BST)可以为{1,0,2,-1},如下图所示:
或为{0,-1,1,#,#,2},如下图所示:
返回任意一种即可.
实例1:
输入:[-1,0,1,2]
返回值:{1,0,2,-1}
实例2:
输入:{}
返回值:{}
//递归方法
class Solution {
public TreeNode sortedArrayToBST (int[] num) {
return dp(num,0,num.length-1);
}
public TreeNode dp(int[] num,int left,int right){
while(left>right){
return null;
}
int val=(left+right)/2;
TreeNode root=new TreeNode(num[val]);
root.left=dp(num,left,val-1);
root.right=dp(num,val+1,right);
return root;
}
}
6.二叉树的最大深度
描述: 求给二叉树的最大深度,深度是指树的根节点到任一叶子节点路径上节点的数量,最大深度是所有叶子节点的深度的最大值.(注:叶子节点是指没有子节点的节点)
数据范围: 0≤n≤100000,树上每个节点的val满足|val|≤100
要求: 空间复杂度O(1),时间复杂度O(n)
实例1:
输入:{1,2}
返回值:2
实例2:{1,2,3,4,#,5}
返回值:3
//递归方法
public class Solution {
public int maxDepth (TreeNode root) {
return root==null?0:Math.max(maxDepth(root.left),maxDepth(root.right))+1;
}
}
7.对称的二叉树
描述:给定一颗二叉树,判断其是否是自身的镜像(即:是否对称)
例如:
下面这棵二叉树是对称的
下面这棵二叉树不对称
数据范围:节点树满足0≤n≤1000,节点上的值满足|val|≤1000
要求:空间复杂度O(n),时间复杂度O(n)
实例1:
输入:{1,2,2,3,4,4,3}
返回值:true
输入:{8,6,9,5,7,7,5}
返回值:false
//递归方法
public class Solution {
boolean isSymmetrical(TreeNode pRoot) {
return check(pRoot,pRoot);
}
boolean check(TreeNode p,TreeNode q){
if(p==null && q==null){
return true;
}else if(p==null || q==null){
return false;
}else{
return p.val==q.val && check(p.left,q.right) && check(p.right,q.left);
}
}
}
8.连续子数组的最大和
描述:输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,子数组最小长度为1,求所有子数组的和的最大值.
数据范围:
1≤n≤2x10^5
-100≤a[i]≤100
要求:时间复杂度O(n),空间复杂度O(n)
进阶:时间复杂度O(n),空间复杂度O(1)
实例1:
输入:[1,-2,3,10,-4,7,2,-5]
返回值:18
实例2:
输入:[2]
返回值:2
实例3:
输入:[-10]
返回值:-10
//优化动态方法
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int sum=0;
int max=array[0];
for(int i=0;i<array.length;i++){
sum=Math.max(sum+array[i],array[i]);
max=Math.max(max,sum);
}
return max;
}
}
9.合并两个有序的数组
描述:给出一个有序的整数数组A和有序的整数数组B,请将数组B合并到数组A中,变成一个有序的升序数组
数据范围:0≤n,m≤100,|Ai|≤100,|Bi|≤100
注意:
1.保证A数组有足够的空间存放B数组的元素,A和B中初始的元素数目分别为m和n,A的数组空间大小为m+n
2.不要返回合并的数组,将数组B的数据合并到A里面就好了
3.A数组在[0,m-1]的范围也是有序的
实例1
输入:[4,5,6],[1,2,3]
返回值:[1,2,3,4,5,6]
实例2:
输入:[1,2,3],[2,5,6]
返回值:[1,2,2,3,5,6]
import java.util.*;
public class Solution {
public void merge(int A[], int m, int B[], int n) {
int len=m+n-1;
int i=m-1;
int j=n-1;
while(i>=0&&j>=0){
if(A[i]>B[j]){
A[len--]=A[i--];
}else {
A[len--]=B[j--];
}
}
while(i>=0){
A[len--]=A[i--];
}
while(j>=0){
A[len--]=B[j--];
}
}
}
10.删除有序链表中重复的元素-I
描述:删除给出链表中的重复元素(链表中元素从小到大有序),使链表中的所有元素都只出现一次
例如:
给出的链表为1->1->2,返回1->2
给出的链表为1->1->2->3->3.返回1->2->3
数据范围:链表长度满足0≤n≤100,链表中任意节点的值满足|val|≤100
进阶:空间复杂度O(1),时间复杂度O(n)
实例1:
输入:{1,1,2}
返回值:{1,2}
实例2:
输入:{}
返回值:{}
public class Solution {
public ListNode deleteDuplicates (ListNode head) {
if(head==null){
return null;
}
ListNode curr=head;
while(curr!=null){
ListNode next=curr.next;
if(next==null){
break;
}
if(curr.val==next.val){
curr.next=next.next;
}else{
curr=next;
}
}
return head;
}
}
11.第一个只出现一次的字符
描述:在一个长为字符串中找到第一个只出现一次的字符,并返回它的位置,如果没有则返回-1(需要区分大小写).(从0开始计数)
数据范围:0≤n≤10000,且字符串只有字母组成
要求:空间复杂度O(n),时间复杂度O(n)
实例1:
输入:"google"
返回值:4
实例2:
输入:"aa"
返回值:-1
import java.util.*;
public class Solution {
public int FirstNotRepeatingChar(String str) {
//判断为字符串空的情况
if(str.length()==0||str==null){
return -1;
}
//创建一个HashMap,统计每个字符出现的次数
HashMap<Character,Integer> map=new HashMap<>();
for(int i=0;i<str.length();i++){
if(!map.keySet().contains(str.charAt(i))){
map.put(str.charAt(i),1);
}else{
map.put(str.charAt(i),map.get(str.charAt(i))+1);
}
}
//找出第一个重复次数为1的字符的位置
for(int i=0;i<str.length();i++){
if(map.get(str.charAt(i))==1){
return i;
}
}
return -1;
}
}
12.求平方根
描述:实现函数int sqrt(int x).
计算并返回x的平方根(向下取整)
数据范围:0<=x<2^31-1
要求:空间复杂度O(1),时间复杂度O(logx)
实例1:
输入:2
返回值:1
实例2:
输入:2143195649
返回值:46294
//直接遍历
public class Solution {
public int sqrt (int x) {
int res=0;
while((long)res * res <= x){
++res;
}
return --res;
}
}
13.合并两个排序的链表
描述:输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的.
数据范围:0≤n≤1000,-1000≤节点值≤1000
要求:空间复杂度O(1),时间复杂度O(n)
如输入{1,3,5},{2,4,6}时,合并后的链表为{1,2,3,4,5,6},所以对应的输出为{1,2,3,4,5,6},如
或输入{-1,2,4},{1,3,4}时,合并后的链表为{-1,1,2,3,4,4},所以对应的输出为{-1,1,2,3,4,4},如
实例1:
输入:{1,3,5},{2,4,6}
返回值:{1,2,3,4,5,6}
实例2:
输入:{},{}
返回值:{}
实例3:
输入:{-1,2,4},{1,3,4}
返回值:{-1,1,2,3,4,4}
//递归方法
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1==null){
return list2;
}
if(list2==null){
return list1;
}
if(list1.val <= list2.val){
list1.next=Merge(list1.next,list2);
return list1;
}else{
list2.next=Merge(list1,list2.next);
return list2;
}
}
}
14.求路径
描述:一个机器人在m x n大小的地图的左上角(起点).
机器人每次可以向下或向右移动.机器人要到达地图的左下角(终点)
可以有多少种不同的路径从起点走到终点?
备注:m和n小于等于100,并保证计算结果在int范围内
数据范围:0<n,m≤100,保证计算结果在32位整型范围内
要求:空间复杂度O(nm),时间复杂度O(nm)
进阶:空间复杂度O(1),时间复杂度O(min(n,m))
实例1:
输入:2,1
返回值:1
实例2:
输入:2,2
返回值:2
public class Solution {
public int uniquePaths (int m, int n) {
int[][] dp=new int[m][n];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i==0||j==0){
dp[i][j]=1;
continue;
}
dp[i][j]=dp[i-1][j]+dp[i][j-1];
}
}
return dp[m-1][n-1];
}
}
15.在旋转过的有序数组中寻找目标值
描述:有一个长度为n的按严格升序排列的整数数组nums,在实行search函数之前,在某个下标k上进行旋转,使数组变为[nums[k],nums[k+1],.....,nums[nums.length-1],nums[0],nums[1],......,nums[k+1]].
给定旋转后的数组nums和一个整数target,请你查找target是否存在于nums数组中并返回其下标(从0开始计数),如果不存在请返回-1.
数据范围:0≤n≤10000,0≤target≤100000
要求:空间复杂度O(1),时间复杂度O(n)
比如,数组[0,2,4,6,8,10]在下标3处旋转之后变为[6,8,10,0,2,4],当给定target为10时,10的下标是2,target为3时,nums数组中不存在3,所以返回-1
实例1:
输入:[6,8,10,0,2,4],10
返回值:2
实例2:
输入:[6,8,10,0,2,4],3
返回值:-1
实例3:
输入:[2],1
返回值:-1
//遍历法
public class Solution {
public int search (int[] nums, int target) {
for(int i=0;i<nums.length;i++){
if(nums[i]==target){
return i;
}
}
return -1;
}
}
//二分查找
public class Solution {
public int search (int[] nums, int target) {
int left=0,right=nums.length-1;
while(left<=right){
int mid=left+(right-left)/2;
if(target==nums[mid]){
return mid;
}
if(nums[left]<=nums[mid]){
if(target<nums[mid] && nums[left]<=target){
right=mid-1;
}else{
left=mid+1;
}
}else{
if(target>nums[mid] && nums[right]>=target){
left=mid+1;
}else{
right=mid-1;
}
}
}
return -1;
}
}
16.有效括号序列
描述:给出一个仅包含字符'(',')','{','}','['和']',的字符串,判断给出的字符串是否是合法的括号序列括号必须以正确的顺序关闭,"()"和"()[]{}"都是合法的括号序列,但"(]"和"([)]"不合法
数据范围:字符串长度0≤n≤10000
要求:空间复杂度O(n),时间复杂度O(n)
实例1:
输入:"{"
返回值:false
实例2:
输入:"[]"
返回值:true
public class Solution {
public boolean isValid (String s) {
Stack<Character> stack=new Stack<>();
char[] chars=s.toCharArray();
for(char c:chars){
if(c=='['||c=='('||c=='{')
stack.push(c);
else{
if(stack.isEmpty()){
return false;
}
else{
char temp=stack.pop();
if(']'==c && temp!='['){
return false;
}
if('}'==c && temp!='{'){
return false;
}
if(')'==c && temp!='('){
return false;
}
}
}
}
return stack.isEmpty();
}
}
17.最长公共前缀
描述:给你一个大小为n的字符串数组strs,其中包含n个字符串,编写一个函数来查找字符串数组中的最长公共前缀,返回这个公共前缀
数据范围:0≤n≤5000,0≤len(strs i)≤5000
进阶:空间复杂度O(n),时间复杂度O(n)
实例1:
输入:["abca","abc","abca","abc","abcc"]
返回值:"abc"
实例2:
输入:["abc"]
返回值:"abc"
public class Solution {
public String longestCommonPrefix (String[] strs) {
if(strs.length==0||strs==null){
return "";
}
int rows=strs.length;
int cols=strs[0].length();
for(int i=0;i<cols;i++){
char firstChar=strs[0].charAt(i);
for(int j=1;j<rows;j++){
if(strs[j].length()==i||strs[j].charAt(i)!=firstChar){
return strs[0].substring(0,i);
}
}
}
return strs[0];
}
}
18.回文数字
描述:在不使用额外的内存空间的条件下判断一个整数是否是回文,回文指逆序和正序完全相同.
数据范围:-2^31≤n≤2^31-1
进阶:空间复杂度O(1),时间复杂度O(len(n))
实例1:
输入:121
返回值:true
实例2:
输入:122
返回值:false
//转为字符串的方法
public class Solution {
public boolean isPalindrome (int x) {
//转为String类型,方便调用功能
String s=String.valueOf(x);
int left=0;
int right=s.length()-1;
while(left<=right){
//判断指针指向的数字是否相同
if(s.charAt(left)==s.charAt(right)){
//相同则移动指针继续判断
left++;
right--;
}else{
return false;
}
}
return true;
}
}
//数学方法
public class Solution {
public boolean isPalindrome (int x) {
if(x < 0) return false;
int result = 0;
int temp = x;
while (temp > 0) {
result = result * 10 + temp % 10;
temp = temp / 10;
}
return x == result;
}
}
19.反转数字
描述:给定一个32位的有符号整数num,将num中的数字部分反转,最后返回反转的结果
1.只反转数字部分,符号为部分不反装
2.反转后整数num超过32位的有符号整数的范围[-2^31,2^31-1],返回0
3.假设本题不允许存储64位整数(有符号位或无符号位,即C++不能使用long long,java不能使用long等)
数据范围:
-2^31<=x<=2^31-1
实例1:
输入:12
返回值:21
实例2:
输入:-123
返回值:-321
实例3:
输入:10
返回值:1
实例4:
输入:1147483649
返回值:0
//数学方法
public class Solution {
public int reverse (int x) {
long n=0;
while(x!=0){
n=n*10+x%10;
x=x/10;
}
return (int)n==n?(int)n:0;
}
}
20.两数之和
描述:给出一个整型数组numbers和一个目标值target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列.(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)
数据范围:2≤len(numbers)≤10^5,-10≤numbers i≤10^9,0≤target≤10^9
要求:空间复杂度O(n),时间复杂度O(nlogn)
实例1:
输入:[3,2,4],6
返回值:[2,3]
实例2:
输入:[20,70,110,150],90
返回值:[1,2]
public class Solution {
public int[] twoSum (int[] numbers, int target) {
int[] sum=new int[2];
for(int i=0;i<numbers.length;i++){
if(numbers[i]>target) continue;
for(int j=i+1;j<numbers.length;j++){
if(numbers[i]+numbers[j]==target){
sum[0]=i+1;
sum[1]=j+1;
return sum;
}
}
}
return sum;
}
}
21.判断是不是平衡二叉树
描述:输入一颗节点为n二叉树,判断该二叉树是否是平衡二叉树.在这里,我们只需要考虑其是不是排序二叉树
平衡二叉树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
举例:
样例二叉树如图,为一颗平衡二叉树
注:我们约定空树是平衡二叉树
数据范围:n ≤ 100,树上节点的val值满足0≤n≤1000
要求:空间复杂度O(1),时间复杂度O(n)
实例1:
输入:{1,2,3,4,5,6,7}
返回值:true
实例2:
输入:{}
返回值:true
public class Solution {
public boolean IsBalanced_Solution(TreeNode root) {
if(root==null) return true;
return Math.abs(maxDepth(root.left)-maxDepth(root.right))<=1 && IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right) ? true : false;
}
public int maxDepth (TreeNode root) {
if(root==null) return 0;
return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
}
}
22.扑克牌顺子
描述:现在有2副扑克牌,从扑克牌中随机五张扑克牌,我们需要来判断一下是不是顺子.
有如下规则:
1.A为1,J为11,Q为12,K为13,A不能视为14
2.大、小王为0.0可以看作任意牌
3.如果给出的五张牌能组成顺子(即这五张牌是连续的)就输出true,否则就输出false.
4.数据保证每组5个数字,每组最多含有4个零,数组的数取值为[0,13]
要求:空间复杂度O(1),时间复杂度O(nlogn),本题也有时间复杂度O(n)的解法
实例1:
输入:[6,0,2,0,4]
返回值:true
实例2:
输入:[0,3,2,6,4]
返回值:true
实例3:
输入:[1,0,0,1,0]
返回值:false
实例4:
输入:[13,12,11,0,1]
返回值:false
import java.util.*;
//遍历相减法
public class Solution {
public boolean IsContinuous(int [] numbers) {
Set<Integer> set = new HashSet<>();
int max = Integer.MIN_VALUE, min =Integer.MAX_VALUE;
//遍历数组
for (int number:numbers) {
if(number == 0) {
continue;
}
//包含相同牌则直接返回,否则加入
if(set.contains(number)){
return false;
}else {
set.add(number);
}
//每次遍历记录最大值,最小值
max = StrictMath.max(max,number);
min = StrictMath.min(min,number);
}
return max - min < 5;
}
}
import java.util.*;
//数组排序法
public class Solution {
public boolean IsContinuous(int [] numbers) {
int king = 0,max,min;
//将数组排序
Arrays.sort(numbers);
for(int i = 0; i < 4; i++) {
//记录王牌个数
if(numbers[i] == 0) king++;
else if(numbers[i] == numbers[i + 1]) return false;
}
max = numbers[4];
min = numbers[king];// king的个数会占去前置位的数组,nums[king]必然是最小值
//最大值和最小值进行比较小于5即是顺子
return numbers[4] - numbers[king] < 5;
}
}
23.两个链表的第一个公共结点
描述:输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空.(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
数据范围:n≤1000
要求:空间复杂度O(1),时间复杂度O(n)
例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:
可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点
实例1:
输入:{1,2,3},{4,5},{6,7}
返回值:{6,7}
实例2:
输入:{1},{2,3},{}
返回值:{}
import java.util.*;
//Set解法
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
Set<ListNode> set=new HashSet<>();
while(pHead1 != null){
set.add(pHead1);
pHead1=pHead1.next;
}
while(pHead2 != null && !set.contains(pHead2)){
pHead2=pHead2.next;
}
return pHead2;
}
}
24.跳台阶
描述:一直青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶共有多少种跳法(先后次序不同算不同的结果)
数据范围:1≤n≤40
要求:时间复杂度:O(n),空间复杂度:O(1)
实例1:
输入:2
返回值:2
实例2:
输入:7
返回值:21
//递归
public class Solution {
public int jumpFloor(int target) {
if(target<=1) return 1;
return jumpFloor(target-1)+jumpFloor(target-2);
}
}
//动态规划
public class Solution {
public int jumpFloor(int target) {
int a=1,b=1,c=1;
for(int i=2;i<=target;i++){
c=a+b; a=b; b=c;
}
return c;
}
}
25.链表中倒数最后k个结点
描述:输入一个长度为n的链表,设链表中的元素的值为ai,返回该链表中倒数第k个节点.如果该链表长度小于k,请返回一个长度为0的链表.
数据范围:0≤n≤10^5,0≤ai≤10^9,0≤k≤10^9
要求:空间复杂度O(n),时间复杂度O(n)
进阶:空间复杂度O(1),时间复杂度O(n)
例如输入{1,2,3,4,5},2时,对应的链表结构如下图所示:
其中蓝色部分为该链表的最好2个结点,所以返回倒数第2个结点(也即结点值为4的结点)即可,系统会打印后面所有的节点来比较.
实例1:
输入:{1,2,3,4,5},2
返回值:{4,5}
实例2:
输入:{2},8
返回值:{ }
//栈方法
public class Solution {
public ListNode FindKthToTail (ListNode pHead, int k) {
Stack<ListNode> stack=new Stack<>();
//链表节点入栈
int count = 0;
while(pHead != null){
stack.push(pHead);
pHead=pHead.next;
count++;
}
if (count<k || k==0) return null;
//在出栈串成新的链表
ListNode firstNode =stack.pop();
while(--k > 0){
ListNode temp=stack.pop();
temp.next=firstNode;
firstNode=temp;
}
return firstNode;
}
}
26.单链表的排序
描述:给定一个节点数为n的无序单链表,对其按升序排序.
数据范围:0<n≤100000
要求:空间复杂度O(n),时间复杂度O(nlogn)
实例1:
输入:[1,3,2,4,5]
返回值:{1,2,3,4,5}
实例2:
输入:[-1,0,-2]
返回值:{-2,-1,0}
public class Solution {
int val;
ListNode next=null;
public ListNode sortInList (ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode fast = head.next;
ListNode slow = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
ListNode tmp = slow.next;
slow.next = null;
ListNode left = sortInList(head);
ListNode right = sortInList(tmp);
ListNode h = new ListNode(0);
ListNode res = h;
while(left != null && right != null){
if(left.val < right.val){
h.next = left;
left = left.next;
}else{
h.next = right;
right = right.next;
}
h = h.next;
}
h.next = left != null ? left:right;
return res.next;
}
}
27.旋转数组的最小数字
描述:有一个长度为n的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的.请问,给定这样一个旋转数组,求数组中的最小值.
数据范围:1≤n≤10000,数组中任意元素的值:0≤val≤10000
要求:空间复杂度:O(1),时间复杂度O(logn)
实例1:
输入:[3,4,5,1,2]
返回值:1
实例2:
输入:[3,100,200,3]
返回值:3
//二分查找
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length==0){
return 0;
}
int left=0;
int right=array.length-1;
while(left<=right){
int mid=left+(right-left)/2;
if(array[mid]>array[right]){
left=mid+1;
}
else if(array[mid]<array[right]){
right=mid;
}else{
right--;
}
}
return array[left];
}
}
28.二叉树的镜像
描述:操作给定的二叉树,将其变换为源二叉树的镜像。
数据范围:二叉树的节点数0≤n≤1000,二叉树每个节点的值0≤val≤1000
要求:空间复杂度O(n)。本题也有原地操作,即空间复杂度O(1)的解法,时间复杂度O(n)
比如:源二叉树
镜像二叉树
实例1:
输入:{8,6,10,5,7,9,11}
返回值:{8,10,6,11,9,7,5}
实例2:
输入:{}
返回值:{}
public class Solution {
public TreeNode Mirror (TreeNode pRoot) {
if(pRoot==null){
return null;
}
TreeNode left=Mirror(pRoot.left);
TreeNode right=Mirror(pRoot.right);
pRoot.left=right;
pRoot.right=left;
return pRoot;
}
}
29.数组中出现次数超过一半的数字
描述:给一个长度为n的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
数据范围:n≤50000,数组中元素的值0≤val≤10000
要求:空间复杂度:O(1),时间复杂度O(n)
实例1:
输入:[1,2,3,2,2,2,5,4,2]
返回值:2
实例2:
输入:[3,3,3,3,2,2,2]
返回值:3
实例3:
输入:[1]
返回值:1
import java.util.*;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
//创建一个hashmap来存入数据对应出现的次数
HashMap<Integer,Integer> hm=new HashMap<Integer,Integer>();
//遍历数据进行比较
for(int i=0;i<array.length;i++){
if(!hm.containsKey(array[i])){
hm.put(array[i],1);
}else{
hm.put(array[i],hm.get(array[i])+1);
}
if(hm.get(array[i])>array.length/2){
return array[i];
}
}
return 0;
}
}
30.数字在升序数组中出现的次数
描述:给定一个长度为n的非降序数组和一个非负数整数k,要求统计k在数组中出现的次数
数据范围:0≤n≤1000,0≤k≤100,数组中每个元素的值满足0≤val≤100
要求:空间复杂度O(1),时间复杂度O(logn)
实例1:
输入:[1,2,3,3,3,3,4,5],3
返回值:4
实例2:
输入:[1,3,4,5],6
返回值:0
//遍历相等法
public class Solution {
public int GetNumberOfK(int[] array , int k) {
int l=0;
for(int i=0;i<array.length;i++){
if(array[i]==k){
l++;
}
}
return l;
}
}
31.用两个栈实现队列
描述:用两个栈来实现一个队列,使用n个元素来完成n次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。队伍中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。
数据范围:n≤1000
要求:存储n个元素的空间复杂度为O(n),插入与删除的时间复杂度都是O(1)
实例1:
输入:["PSH1","PSH2","pop","pop"]
返回值:1,2
实例2:
输入:["PSH2","pop","PSH1","pop"]
返回值:2,1
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
//入栈
public void push(int node) {
stack1.push(node);
}
//出栈
public int pop() {
if(stack2.size()<=0){
while(stack1.size()>0){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}
32.反转链表
描述:给定一个但链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
数据范围:0≤n≤1000
要求:空间复杂度O(1),时间复杂度O(n)
如当输入链表{1,2,3}时,经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。以上转换过程如下图所示:
实例1:
输入:{1,2,3}
返回值:{3,2,1}
实例2:
输入:{}
返回值:{}
public class Solution {
public ListNode ReverseList(ListNode head) {
//反转节点pre
ListNode pre=null;
//当前节点cur
ListNode cur=head;
while(cur!=null){
//下一节点 next
ListNode next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
}
33.字符串变形
描述:对于一个长度为n字符串,我们需要对它做一些变形。首先这个字符串中包含着一些空格,就像“Hello World”一样,然后我们要做的是把这个字符串中由空格隔开的单词反序,同时反转每个字符的大小写。比如“Hello World”变形后就变成了“wORLDhELLO”。
数据范围:1≤n≤10^6,字符串中包含大写英文字母、小写英文字母、空格。
进阶:空间复杂度O(n),时间复杂度O(n)
实例1:
输入:“This is a sample”,16
返回值:“SAMPLE A IS tHis”
import java.util.*;
public class Solution {
public String trans(String s, int n) {
if(n==0){
return s;
}
StringBuffer res=new StringBuffer();
for(int i=0;i<n;i++){
//大小写转换
if(s.charAt(i)>='A' && s.charAt(i)<='Z'){
res.append((char)(s.charAt(i)-'A'+'a'));
}else if(s.charAt(i)>='a' && s.charAt(i)<='z'){
res.append((char)(s.charAt(i)-'a'+'A'));
}else{
//空格不作处理
res.append(s.charAt(i));
}
}
//翻转字符串
res=res.reverse();
for(int i=0;i<n;i++){
int j=i;
//空格为界 二次翻转
while(j<n && res.charAt(j) !=' '){
j++;
}
String temp=res.substring(i,j);
StringBuffer buffer=new StringBuffer(temp);
temp=buffer.reverse().toString();
res.replace(i,j,temp);
i=j;
}
return res.toString();
}
}
34.包含min函数的栈
描述:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数,输入操作时保证pop、top和min函数操作时,栈中一定有元素。
此栈包含的方法有:
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素
数据范围:操作数量满足0≤n≤300,输入的元素满足|val|≤10000
进阶:栈的各个操作的时间复杂度是O(1),空间复杂度是O(n)
实例:
输入: ["PSH-1","PSH2","MIN","TOP","POP","PSH1","TOP","MIN"]
输出: -1,2,1,-1
解析:
"PSH-1"表示将-1压入栈中,栈中元素为-1
"PSH2"表示将2压入栈中,栈中元素为2,-1
“MIN”表示获取此时栈中最小元素==>返回-1
"TOP"表示获取栈顶元素==>返回2
"POP"表示弹出栈顶元素,弹出2,栈中元素为-1
"PSH1"表示将1压入栈中,栈中元素为1,-1
"TOP"表示获取栈顶元素==>返回1
“MIN”表示获取此时栈中最小元素==>返回-1
import java.util.Stack;
public class Solution {
//正常栈
Stack<Integer> stack=new Stack<Integer>();
//最小值栈
Stack<Integer> min=new Stack<Integer>();
public void push(int node) {
stack.push(node);
//最小值栈入栈
if(min.isEmpty() || node<=min.peek()){
min.push(node);
}
}
public void pop() {
//栈顶元素相同时最小值栈顶也得弹出
if(stack.peek().equals(min.peek())){
min.pop();
}
stack.pop();
}
public int top() {
return stack.peek();
}
public int min() {
return min.peek();
}
}
35.判断一个链表是否为回文结构
给定一个链表,请判断该链表是否为回文结构。回文是指该字符串正序逆序完全一致。
数据范围:链表节点树0≤n≤10^5,链表中每个节点的值满足|val|≤10^7
实例1:
输入:{1}
返回值:true
实例2:
输入:{2,1}
返回值:false
实例3:
输入:{1,2,2,1}
返回值:true
public class Solution {
public boolean isPail (ListNode head) {
ArrayList<Integer> nums=new ArrayList();
//用数组来存入链表的元素
while(head!=null){
nums.add(head.val);
head=head.next;
}
//创建一个翻转的数组
ArrayList<Integer> newNums=new ArrayList();
newNums=(ArrayList<Integer>)nums.clone();
Collections.reverse(newNums);
//正反比较
for(int i=0;i<nums.size();i++){
int x=nums.get(i);
int y=newNums.get(i);
if(x != y){
return false;
}
}
return true;
}
}
36.判断t1树中是否有与t2树完全相同的字树
描述:给定彼此独立的两颗二叉树,树上的节点值两两不同,判断t1树是否有与t2树完全相同的字树。字树指一棵树的某个节点的全部后继节点
数据范围:树的节点树满足0<n<5000000.树上每个节点的值一定在32位整型范围内
进阶:空间复杂度O(n),时间复杂度O(n)
实例1:
输入:{1,2,3,4,5,6,7,#,8,9},{2,4,5,#,8,9}
返回值:true
import java.util.*;
public class Solution {
public boolean isContains (TreeNode root1, TreeNode root2) {
//如果t1遍历完还没有找到t2,直接返回false
if(root1==null) return false;
//遍历t1子树,和t2比较是否相等
return equals(root1,root2)||isContains(root1.left,root2)||isContains(root1.right,root2);
}
//判断两棵树是否相等
private boolean equals(TreeNode root1,TreeNode root2){
if(root1==null&&root2==null) return true;
if(root1==null||root2==null) return false;
return root1.val==root2.val&&equals(root1.left,root2.left)&&equals(root1.right,root2.right);
}
}
37.压缩字符串(一)
描述:利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2bv5a3。
1.如果只有一个字符,1不用写
2.字符串中只包含大小写英文字母(a至z)。
数据范围:
0<=字符串长度<=50000
要求:时间复杂度O(N)
实例1:
输入:“shopeew”
返回值:“shope2w”
public class Solution {
public String compressString (String param) {
if(param.equals("")||param.length()==1){
return param;
}
int num=1; //字母长度
char c=param.charAt(0); //第一个字符
StringBuffer sb=new StringBuffer(); //存入新字符串
for(int i=1;i<param.length();i++){
if(c==param.charAt(i)){
num++;
}else {
sb.append(c);
if(num>1){
sb.append(num);
}
num=1;
c=param.charAt(i);
}
if(i==param.length()-1){
sb.append(c);
if(num>1){
sb.append(num);
}
}
}
return sb.toString();
}
}
38.三个数的最大乘积
4描述:给定一个长度为n的无序数组A,包含正数,负数和0,请从中找出3个数,使得乘积最大,返回这个乘积。
要求:时间复杂度:O(n),空间复杂度:O(1)
数据范围:3≤n≤10^ -10^4≤A|i|≤10^4
实例1:
输入:[3,4,1,2]
返回值:24
public class Solution {
public long solve (int[] A) {
if(A==null&&A.length<3){
return 0;
}
Arrays.sort(A);
long result1=(long)A[0]*A[1]*A[A.length-1];
long result2=(long)A[A.length-1]*A[A.length-2]*A[A.length-3];
return Math.max(result1,result2);
}
}
39.进制转换
描述:
给定一个十进制数 M ,以及需要转换的进制数 N 。将十进制数 M 转化为 N 进制数。当 N 大于 10 以后, 应在结果中使用大写字母表示大于 10 的一位,如 'A' 表示此位为 10 , 'B' 表示此位为 11 ,若 M 为负数,应在结果中保留负号。
数据范围: M <= 10^8 , 2≤ N ≤ 16
要求:空间复杂度O(logMN)O(logMN),时间复杂度 O(logMN)O(logMN)
实例1:
输入:7,2
返回值:“111”
实例2:
输入:10,16
返回值:“A”
public class Solution {
public String solve (int M, int N) {
StringBuilder res=new StringBuilder();
String str=M<0?"-":"";
M=Math.abs(M);
while(M>0){
int num=M%N; //获取余数
if(num>=10){
res.append((char)(num-10+'A'));
}else{
res.append(num);
}
M=M/N; //获取整除数
}
res.append(str);
return res.reverse().toString();
}
}
40.旋转字符串
描述:字符串旋转:给定两字符串A和B,如果能将A从中间某个位置分割为左右两部分字符串(可以为空串),并将左边的字符串移动到右边字符串后面组成新的字符串可以变为字符串B时返回true。
例如:如果A='youzan',B=‘zanyou’,A按‘you’‘zan’切割换位后得到‘zanyou’和B相同,返回true。再如:如果A=‘abcd’,B=‘abcd’,A切成‘abcd’和''(空串),换位后可以得到B,返回true。
数据范围:A,B字符串长度满足 n≤1000,保证字符串中仅包含小写英文字母和阿拉伯数字
进阶: 时间复杂度 O(n),空间复杂度O(n)
public class Solution {
public boolean solve (String A, String B) {
if(A.length()!=B.length()){
return false;
}
A=A+A;
return A.indexOf(B)>=0?true:false;
}
}
41.合并二叉树
描述:已知两颗二叉树,将它们合并成一颗二叉树。合并规则是:都存在的结点,就将结点值加起来,否则空的位置就由另一个树的结点来代替。例如:
数据范围:树上节点数量满足0≤n≤500,树上节点的值一定在32位整型范围内。
进阶:空间复杂度O(1),时间复杂度O(n)
实例1:
输入:{1,3,2,5},{2,1,3,#,4,#,7}
返回值:{3,4,5,5,4,#,7}
public class Solution {
public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {
//考虑特殊情况 空
if(t1==null){
return t2;
}
if(t2==null){
return t1;
}
//递归
TreeNode head = new TreeNode(t1.val+t2.val);
head.left=mergeTrees(t1.left,t2.left);
head.right=mergeTrees(t1.right,t2.right);
return head;
}
}
42.二进制中1的个数
描述:输入一个整数n,输出改数32位二进制表示中1的个数。其中负数用补码表示。
数据范围:-2^31<=n<=2^31-1,即范围为:-2147483648<=n<=2147483647
实例1:
输入:10
返回值:2
实例2:
输入:-1
返回值:32
public class Solution {
public int NumberOf1(int n) {
int res=0;
while(n != 0){
res +=(n & 1); //n&1表示n与1相与
n >>>=1; //>>>表示无符号右移
}
return res;
}
}
43.排序
描述:给定一个长度为 n 的数组,请你编写一个函数,返回该数组按升序排序后的结果。
数据范围: 0 ≤ n ≤1x10^3,数组中每个元素都满足 0≤val≤10^9
要求:时间复杂度 O(n^2),空间复杂度 O(n)
进阶:时间复杂度 O(nlogn),空间复杂度 O(n)
注:本题数据范围允许绝大部分排序算法,请尝试多种排序算法的实现。
实例1:
输入:[5,2,3,1,4]
返回值:[1,2,3,4,5]
import java.util.*;
//快速排序
//原理:数组第一个值作为中枢,使得小于中枢的值放在左边,大于中枢的值放在右边
public class Solution {
public int[] MySort(int[] arr){
quickSort(arr,0,arr.length-1);
return arr;
}
public static void quickSort (int[] arr,int left,int right) {
if(left < right){
int i=left;
int j=right;
int pivot=arr[i];
while(i<j){
while(i<j && arr[j]>=pivot){
j--;
}
if(i<j){
arr[i]=arr[j];
}
while(i<j && arr[i]<=pivot){
i++;
}
if(i<j){
arr[j]=arr[i];
}
}
arr[i] = pivot; //循环结束,此时i=j,为无效数据,重新赋值
quickSort(arr,left,i-1); //pivot向左的继续排
quickSort(arr,i+1,right);
}
}
}
44.两个二进制的不同位数
描述:两个int32整数m和n的二进制表达,有多少个位(bit)不同。
输入:3,5
返回值:2
public class Solution {
public int countBitDiff (int m, int n) {
int ans=0;
while(m!=0||n!=0){
if((m & 1) != (n & 1)){
ans++;
}
m>>=1;
n>>=1;
}
return ans;
}
}
45.01背包
描述:已知一个背包最多能容纳体积之和为v的物品。现有 n 个物品,第 i 个物品的体积为 vi , 重量为 wi,求当前背包最多能装多大重量的物品?
数据范围:1≤v≤1000;1≤n≤1000,1≤vi≤1000,1≤wi≤1000
进阶:O(nv)
实例1:
输入:10,2,[[1,3],[10,4]]
返回值:4
public class Solution {
/**
* @param V int整型 背包的体积
* @param n int整型 物品的个数
* @param vw int整型二维数组 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
* @return int整型
*/
public int knapsack (int V, int n, int[][] vw) {
int[] dp = new int[V+1];
for (int i = 0; i < n; i++) {
int vi = vw[i][0], wi = vw[i][1];
for (int j = V; j >= vi; j--) {
dp[j] = Math.max(dp[j], dp[j-vi]+wi);
}
}
return dp[V];
}
}
46.几步可以从头跳到尾
描述:给你一个长度为n的数组a。ai 表示从 i 这个位置开始最多能往后跳多少格。求从 1 开始最少需要跳几次就能到达第 n 个格子。
数据范围: 1 ≤n≤100000 , 1 ≤ai≤1000000000
进阶: 空间复杂度O(1) , 时间复杂度 O(n)
实例1:
输入:2,[1,2]
返回值:1
实例2:
输入:3,[2,3,1]
返回值:1