NC刷题笔记2-数组

本博客文章(学习笔记)导航 (点击这里访问)
在这里插入图片描述

NC1 大数之和

描述
以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。

数据范围:len(s),len(t),len(s),len(t)≤100000,字符串仅由'0'~‘9’构成
要求:时间复杂度 O(n)

示例1
输入:"1","99"
返回值:"100"
说明:1+99=100     

示例2
输入:"114514",""
返回值:"114514"
思路:
	合并数组
import java.util.*;
public class Solution {
    public String solve (String s, String t) {
        //判空处理
        if(s.equals("")||s==null) return t;
        if(t.equals("")||t==null) return s;
        //字符串反转 方便加和
        s=strReverse(s);
        t=strReverse(t);
        //获取最短数组
        char[] s0=s.toCharArray();
        char[] s1=t.toCharArray();
        int fornum=s0.length>=s1.length?s1.length:s0.length;
        //结果
        StringBuffer sb=new StringBuffer();
        int add=0;//进位
        //合并数组
        for(int i=0;i<fornum;i++){
            Integer num1=(int)(s.charAt(i)-'0');
            Integer num2=(int)(t.charAt(i)-'0');
            Integer sum=num2+num1+add;
            sb.append(sum%10);
            add=sum/10;
        }
        //剩余部分
        if(s0.length>fornum){
            for(int i=fornum;i<s0.length;i++){
                Integer num1=(int)(s.charAt(i)-'0');
                Integer sum=num1+add;
                sb.append(sum%10);
                add=sum/10;
            }
        }
        //剩余部分
        if(s1.length>fornum){
            for(int i=fornum;i<s1.length;i++){
                Integer num1=(int)(t.charAt(i)-'0');
                Integer sum=num1+add;
                sb.append(sum%10);
                add=sum/10;
            }
        }
        //加上进位
        if(add!=0) sb.append(add+"");
        sb=sb.reverse();
        return sb.toString();
    }
    
    //反转字符串
    public String strReverse(String str){
        if(str.length()==0||str.length()==1) return str;
        StringBuilder sb=new StringBuilder(str);
        sb.reverse();
        return sb.toString();
    }
}

NC7 买卖股票的最佳时机(一)

描述
假设你有一个数组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
思路1:
	找到差值最大的两个数,后面的那个数比前面的大
思路2:
	动态规划
	当天持有股票:前天持有股票或者今天刚买
	当天不持有股票:前天不持有股票或者前天持有今天刚卖
思路1import java.util.*;
public class Solution {
    public int maxProfit (int[] prices) {
        if(prices.length<2) return 0;
        int max=0;
        for(int i=0;i<prices.length-1;i++){
            int n1=prices[i];
            for(int j=i+1;j<prices.length;j++){
                max=Math.max(max,prices[j]-n1);
            }
        }
        return max;
    }
}
思路2import java.util.*;
public class Solution {
    public int maxProfit (int[] prices) {
        int[][] dp=new int[prices.length][2];
        dp[0][0]=0;
        dp[0][1]=-prices[0];
        for(int i=1;i<prices.length;i++){
            dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);
            dp[i][1]=Math.max(dp[i - 1][1], -prices[i]);
        }
        return dp[prices.length-1][0];
    }
}

NC12 重建二叉树

描述
给定节点数为 n 二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。
提示:
1.vin.length == pre.length
2.pre 和 vin 均无重复元素
3.vin出现的元素均出现在 pre里
4.只需要返回根结点,系统会自动输出整颗树做答案对比
数据范围:0n≤2000,节点的值 0≤val≤10000
要求:空间复杂度 O(n),时间复杂度 O(n)
import java.util.*;
public class Solution {
    static HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
    static int[] pre;
    public TreeNode reConstructBinaryTree(int [] pre,int [] vin) {
        this.pre=pre;
        for(int i=0;i<vin.length;i++){
            map.put(vin[i],i);
        }
        return recur(0,0,vin.length-1);
    }
     
    public TreeNode recur(int pre_index,int vin_left,int vin_right){
        if(vin_left>vin_right) return null;
        TreeNode root=new TreeNode(pre[pre_index]);
        int root_index=map.get(pre[pre_index]);
        root.left=recur(pre_index+1,vin_left,root_index-1);
        root.right=recur(pre_index+root_index-vin_left+1,root_index+1,vin_right);
        return root;
    }
}

NC18 顺时针旋转数组

n为矩阵的长和宽
输入:[[1,2,3],[4,5,6],[7,8,9]],3 
返回值:[[7,4,1],[8,5,2],[9,6,3]]
思路:
	直接求解res[j][n-i-1]=mat[i][j]
import java.util.*;
public class Solution {
    public int[][] rotateMatrix(int[][] mat, int n) {
        int[][] res=new int[n][n];
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                res[j][n-i-1]=mat[i][j];
            }
        }
        return res;
    }
}

NC 22 合并两个有序数组

描述
给出一个有序的整数数组 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]

说明:
A数组为[4,5,6],B数组为[1,2,3],后台程序会预先将A扩容为[4,5,6,0,0,0],B还是为[1,2,3],m=3,n=3,传入到函数merge里面,然后请同学完成merge函数,将B的数据合并A里面,最后后台程序输出A数组           
示例2
输入:[1,2,3],[2,5,6]
返回值:[1,2,2,3,5,6]
思路:
	1 倒着填充,谁大填谁
	2 当A没填完直接返回
	3 B没填充完,再开一个for循环填充即可
import java.util.*;
public class Solution {
    public void merge(int A[], int m, int B[], int n) {
        int left=m-1,right=n-1;
        for(int i=A.length-1;i>=0&&left>=0&&right>=0;i--){
            if(A[left]>B[right]){
                A[i]=A[left];
                left--;
            }else{
                A[i]=B[right];
                right--;
            }
        }
        if(right!=-1){
            for(int i=right;i>=0;i--){
                A[i]=B[i];
            }
        }
    }
}

NC 27 集合的所有子集(一)

描述
现在有一个没有重复元素的整数集合S,求S的所有子集
注意:
你给出的子集中的元素必须按升序排列
给出的解集中不能出现重复的元素

数据范围:1≤n≤5,集合中的任意元素满足 ∣val∣≤10
要求:空间复杂度 O(n!),时间复杂度 O(n!)
示例1
输入:[1,2,3]
返回值:[[],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]
示例2
输入:[]
返回值:[]
思路:
	1 回溯
	2 终止条件:index越界开始添加
	3 每个index有两个选择:添加和不添加
import java.util.*;
public class Solution {
    public ArrayList<ArrayList<Integer>> subsets(int[] S) {
        ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
        if(S.length==0) return res;
        recur(res,S,new ArrayList<Integer>(),0);
        return res;
    }
    
    public void recur(ArrayList<ArrayList<Integer>> res,int[] S,ArrayList<Integer> temp,int index){
        if(index>=S.length){
            res.add(new ArrayList<Integer>(temp));
            return;
        }
        temp.add(S[index]);
        recur(res,S,temp,index+1);
        temp.remove(temp.size()-1);
        recur(res,S,temp,index+1);
    }
}

NC 29 二维数组中查找

描述
在一个二维数组array中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
[[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]]
给定 target = 7,返回 true。
给定 target = 3,返回 false。

数据范围:矩阵的长宽满足0≤n,m≤500 , 矩阵中的值满足0≤val≤10
 
进阶:空间复杂度 O(1),时间复杂度 O(n+m)
示例1
输入:7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
返回值:true

说明:
存在7,返回true   
示例2
输入:1,[[2]]
返回值:false
思路:
	可以看成一个二叉搜索树
	以右上角的值为根节点
public class Solution {
    public boolean Find(int target, int [][] array) {
        int i=0,j=array[0].length-1;
        return judge(target,array,i,j);
    }
   
    public boolean judge(int target, int [][] array,int i,int j){
        if(i>=array.length||j<0) return false;
        if(target==array[i][j]){
            return true;
        }else if(target>array[i][j]){
            return judge(target,array,i+1,j);
        }else{
            return judge(target,array,i,j-1);
        }
    }
}

NC 30 缺失的第一个数字

描述
给定一个无重复元素的整数数组nums,请你找出其中没有出现的最小的正整数
进阶: 空间复杂度 O(1),时间复杂度 O(n)

数据范围:
-2^31<=nums[i]<=2^31-1
0<=len(nums)<=5*10^5
示例1
输入:[1,0,2]
返回值:3

示例2
输入:[-2,3,4,1,5]
返回值:2

示例3
输入:[4,5,6,8,9]
返回值:1
思路1:
	HashSet 保存,再次遍历1-nums.length
	时间复杂度:O(n)
	空间复杂度:O(n)
思路2:
	排序,从第一个正数处开始判断
	时间复杂度:O(nlog(n))
	空间复杂度:O(1)
思路1import java.util.*;
public class Solution {
    public int minNumberDisappeared (int[] nums) {
        HashSet<Integer> set=new HashSet();
        for(int i:nums) set.add(i);
        for(int i=1;i<=nums.length;i++){
            if(!set.contains(i)){
                return i;
            }
        }
        return nums.length+1;
    }
}
思路2import java.util.*;
public class Solution {
    public int minNumberDisappeared (int[] nums) {
        Arrays.sort(nums);
        int noSub=-1;
        for(int i=0;i<nums.length;i++){
            if(nums[i]>0&&noSub<0) noSub=i;
            if(nums[i]>0){
                if(nums[i]!=(i-noSub+1)) return i-noSub+1;
            }
        }
        return nums[nums.length-1]+1;
    }
}

NC 36 在两个长度相等的排序数组中找到上中位数

描述
给定两个递增数组arr1和arr2,已知两个数组的长度都为N,求两个数组中所有数的上中位数。
上中位数:假设递增序列长度为n,为第n/2个数

数据范围:1≤n≤10,0≤arr≤10^9
 
要求:时间复杂度 O(n),空间复杂度 O(1)
进阶:时间复杂度为O(logN),空间复杂度为O(1)

示例1
输入:[1,2,3,4],[3,4,5,6]
返回值:3
说明:总共有8个数,上中位数是第4小的数,所以返回3。   

示例2
输入:[0,1,2],[3,4,5]
返回值:2
说明:总共有6个数,那么上中位数是第3小的数,所以返回2
思路:
	相当于合并数组
	找到合并后的第arr1.length个元素
import java.util.*;
public class Solution {
    public int findMedianinTwoSortedAray (int[] arr1, int[] arr2) {
        if(arr1.length==1) return Math.min(arr1[0],arr2[0]);
        int aim=arr1.length; //找到该位置时结束
        int Nom=0;
        int left=0,right=0;
        while(left<arr1.length&&right<arr2.length){
            if(arr1[left]<arr2[right]){
                left++;
                Nom++;
                if(Nom==aim) return arr1[left-1];
            }else{
                right++;
                Nom++;
                if(Nom==aim) return arr2[right-1];
            }
        }
        while(left<arr1.length){
            left++;
            Nom++;
            if(Nom==aim) return arr1[left-1];
        }
        while(right<arr2.length){
            right++;
            Nom++;
            if(Nom==aim) return arr2[right-1];
        }
        return 0;
    }
}

NC 37合并区间

描述:给出一组区间,请合并所有重叠的区间。请保证合并后的区间按区间起点升序排列。

数据范围:区间组数0≤n≤1000,区间内 的值都满足0≤val≤10000
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
进阶:空间复杂度 O(val),时间复杂度O(val)

示例1
输入:[[10,30],[20,60],[80,100],[150,180]]
返回值:[[10,60],[80,100],[150,180]]

示例2
输入:[[0,10],[10,20]]
返回值:[[0,20]]
思路:
	1 排序(start从小到大)
	2 前后指针 比较i的end和(i+1)的start和end的值进行合并
	3 删除多余的元素
import java.util.*;
/**
 * Definition for an interval.
 * public class Interval {
 *     int start;
 *     int end;
 *     Interval() { start = 0; end = 0; }
 *     Interval(int s, int e) { start = s; end = e; }
 * }
 */
public class Solution {
    public ArrayList<Interval> merge(ArrayList<Interval> intervals) {
        ArrayList<Interval> res=new ArrayList<>();
        if(intervals.size()<2) return intervals;
        Collections.sort(intervals,(a,b)->a.start-b.start);
        for(int i=0;i<intervals.size()-1;i++){
            if(intervals.get(i).end>=intervals.get(i+1).start){
                intervals.set(i+1,new Interval(intervals.get(i).start,Math.max(intervals.get(i+1).end,intervals.get(i).end)));
            }else{
                res.add(intervals.get(i));
            }
        }
        res.add(intervals.get(intervals.size()-1));
        return res;
    }
}

NC 38 螺旋矩阵

示例1
输入:[[1,2,3],[4,5,6],[7,8,9]]
返回值:[1,2,3,6,9,8,7,4,5]

示例2
输入:[]
返回值:[]
思路:
	模拟法:按圈打印
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> spiralOrder(int[][] matrix) {
        ArrayList<Integer> res=new ArrayList<Integer>();
        if(matrix.length==0||matrix[0].length==0) return res;
        int row=matrix.length,column=matrix[0].length;
        int x1=0,y1=0,x2=column-1,y2=row-1;
        while(x1<=x2&&y1<=y2){
            for(int i=x1;i<=x2;i++){
                res.add(matrix[y1][i]);
            }
            for(int i=y1+1;i<=y2;i++){
                res.add(matrix[i][x2]);
            }
            if(x1!=x2&&y1!=y2){
                for(int i=x2-1;i>=x1;i--){
                    res.add(matrix[y2][i]);
                }
                for(int j=y2-1;j>=y1+1;j--){
                    res.add(matrix[j][x1]);
                }
            }
            x1++;
            y1++;
            x2--;
            y2--;
        }
        return res;
    }
}

NC41 最长无重复子数组

示例1
输入:[2,3,4,5]
返回值:4
说明:[2,3,4,5]是最长子数组      

示例2
输入:[2,2,3,4,3]
返回值:3
说明:[2,3,4]是最长子数组      

示例3
输入:[9]
返回值:1

示例4
输入:[1,2,3,1,2,3,2,2]
返回值:3
说明:最长子数组为[1,2,3]
思路1:
	滑动窗口
	时间复杂度:O(n)
	空间复杂度:O(n)
import java.util.*;
public class Solution {
    public int maxLength (int[] arr) {
        if(arr.length < 2) return arr.length;
        HashMap<Integer, Integer> windows = new HashMap<>();
        int res = 0;
        int left = -1;
        for(int right = 0; right < arr.length; right++){
            if(windows.containsKey(arr[right])){
                left = Math.max(left, windows.get(arr[right]));
            }
            res = Math.max(res, right-left);
            windows.put(arr[right], right);
        }
        return res;
    }
}

NC46 加起来和为目标值的组合(二)

要求:空间复杂度 O(n!), 时间复杂度 O(n!)

示例1
输入:[100,10,20,70,60,10,50],80
返回值:[[10,10,60],[10,20,50],[10,70],[20,60]]
说明:给定的候选数集是[100,10,20,70,60,10,50],目标数是80 

示例2
输入:[2],1
返回值:[]
import java.util.*;
public class Solution {
    public ArrayList<ArrayList<Integer>> combinationSum2(int[] num, int target) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
        ArrayList<Integer> arr = new ArrayList<Integer>();
        if(num == null || num.length==0 || target<0) return res;
        Arrays.sort(num);//对候选数组进行排序 方便后续处理
        dfs(num,target,res,arr,0);
        return res;
    }
    void dfs(int[] num,int target,ArrayList<ArrayList<Integer>> res,ArrayList<Integer> arr,int start){
        if(target==0){
            //已找到一组 存储进res
            res.add(new ArrayList<Integer>(arr));
            return;
        }
        if(start >= num.length)return;
        for(int i=start;i<num.length;i++){
            if(i > start && num[i] == num[i-1])continue;
            //回溯操作
            if(num[i] <= target){
                arr.add(num[i]);
                dfs(num,target-num[i],res,arr,i+1);
                arr.remove(arr.size()-1);
            }
        }
        return;
    }
}

NC54 数组中相加和为0的三元组

空间复杂度:O(n^2,时间复杂度 O(n^2)
示例1
输入:[0]
返回值:[]

示例2
输入:[-2,0,1,1,2]
返回值:[[-2,0,2],[-2,1,1]]

示例3
输入:[-10,0,10,20,-10,-40]
返回值:[[-10,-10,20],[-10,0,10]]
思路:
	for循环+左右指针
import java.util.*;
public class Solution {
    public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
        ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
        if(num.length<3) return res;
        Arrays.sort(num);
        for(int i=0;i<num.length-2;i++){
            if(i>0&&num[i]==num[i-1]) continue;
            int left=i+1,right=num.length-1;
            while(left<right){
                if((num[i]+num[left]+num[right])==0){
                    ArrayList<Integer> temp=new ArrayList<>();
                    temp.add(num[i]);
                    temp.add(num[left]);
                    temp.add(num[right]);
                    res.add(temp);
                    while(left<right&&num[left]==num[++left]);
                    while(left<right&&num[right]==num[--right]);
                }else if((num[i]+num[left]+num[right])>0){
                    right--;
                }else{
                    left++;
                }
            }
        }
        return res;
    }
}

NC59 矩阵的最小路径和

给定一个n*m 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。
数据范围:0<n,m≤50,矩阵中任意值都满足0<ai,aj≤100
要求:空间复杂度O(1),时间复杂度O(nm)

示例1
输入:[[1,3,5,9],[8,1,3,4],[5,0,6,1],[8,8,4,0]]
返回值:12

示例2
输入:[[1,2,3],[1,2,3]]
返回值:7
思路1:(可以满足复杂度要求)
	动态规划:dp[i][j]=matrix[i][j]+Math.min(dp[i-1][j],dp[i][j-1])
思路2:(超时)
	递归:minPath(grid,grid.length-1,grid[0].length-1)=grid[i][j] + Math.min(minPathSum(grid,i-1,j), minPathSum(grid,i,j-1))
思路一:
import java.util.*;
public class Solution {
    public int minPathSum(int[][] grid) {
        if(grid.length==0||grid[0].length==0) return 0;
        for(int i=0;i<grid.length;i++){
            for(int j=0;j<grid[0].length;j++){
                if(i==0&&j==0){
                    continue;
                }else if(i==0&&j!=0){
                    grid[i][j]=grid[i][j]+grid[i][j-1];
                }else if(i!=0&&j==0){
                    grid[i][j]=grid[i][j]+grid[i-1][j];
                }else{
                    grid[i][j]=grid[i][j]+Math.min(grid[i][j-1],grid[i-1][j]);
                }
            }
        }
        return grid[grid.length-1][grid[0].length-1];
    }
}
思路二:超时
import java.util.*;
public class Solution {
    public int minPathSum(int[][] grid) {
        return minPathSum(grid, grid.length - 1, grid[0].length - 1);
    }
    public int minPathSum(int[][] grid, int i, int j) {
        if (i == 0 && j == 0) return grid[i][j];
        //第一行只能从左边走过来
        if (i == 0) return grid[i][j] + minPathSum(grid, i, j - 1);
        //第一列只能从上面走下来
        if (j == 0) return grid[i][j] + minPathSum(grid, i - 1, j);
        //取从上面走下来和从左边走过来的最小值+当前坐标的值
        return grid[i][j] + Math.min(minPathSum(grid, i - 1, j), minPathSum(grid, i, j - 1));
    }
}

NC61 两数之和

描述
给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。(注:返回的数组下标从1开始算起)

数据范围:2≤len(numbers)≤1500,-10≤numbers≤10^9, 0≤target≤10^9
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
例如:
给出的数组为 [20,70,110,150],目标值为90

返回一个数组 [1,2] ,因为numbers1+numbers 2=20+70=90
示例1
输入:[3,2,4],6
返回值:[2,3]
说明:因为 2+4=6 ,而 2的下标为2 , 4的下标为3 ,又因为 下标2 < 下标3 ,所以返回[2,3]         
示例2
输入:[20,70,110,150],90
返回值:[1,2]
import java.util.*;
public class Solution {
    public int[] twoSum (int[] numbers, int target) {
        if(numbers.length<2) return null;
        HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
        for(int i=0;i<numbers.length;i++){
            if(map.containsKey(target-numbers[i])){
                return new int[]{map.get(target-numbers[i]),i+1};
            }
            map.put(numbers[i],i+1);
        }
        return null;
    }
}

NC65 斐波那契数列

描述
大家都知道斐波那契数列,现在要求输入一个正整数 n ,请你输出斐波那契数列的第 n 项。斐波那契数列是一个满足 fib(x)=fib(x−1)+fib(x−2) 的数列
数据范围:1≤n≤39要求:空间复杂度 O(1),时间复杂度 O(n) ,本题也有时间复杂度 O(logn) 的解法

输入描述:一个正整数n
返回值描述:输出一个正整数。

示例1
输入:4
返回值:3
说明:根据斐波那契数列的定义可知,fib(1)=1,fib(2)=1,fib(3)=fib(3-1)+fib(3-2)=2,fib(4)=fib(4-1)+fib(4-2)=3,所以答案为4。  

示例2
输入:1
返回值:1

示例3
输入:2
返回值:1
思路1:
	递归写法 空间复杂度O(1) 时间复杂度O(2^n)
思路2:
	动态规划 空间复杂度O(n) 时间复杂度O(n)
思路3:
	动态规划改进写法,运算当前值只需要两个数即可  时间复杂度O(n)
思路1public class Solution {
    public int Fibonacci(int n) {
        if(n==1||n==2) return 1;
        return Fibonacci(n-1)+Fibonacci(n-2);
    }
}
思路2public class Solution {
    public int Fibonacci(int n) {
        if(n==1||n==2) return 1;
        int[] dp=new int[n+1];
        dp[1]=1;
        dp[2]=1;
        for(int i=3;i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
}
思路3public class Solution {
    public int Fibonacci(int n) {
        if(n==1||n==2) return 1;
        int a=1,b=1,c=a+b;
        for(int i=3;i<=n;i++){
            c=a+b;
            a=b;
            b=c;
        }
        return b;
    }
}

NC73 数组中出现次数超过一半的数字

描述
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
数据范围:0≤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
思路1:
	快速排序输出最中间的值 空间复杂度:O(1),时间复杂度 O(nlog(n))
思路2:
	hashmap 空间复杂度:O(n),时间复杂度 O(n)
思路3:
	候选法:
	加入数组中存在众数,那么众数一定大于数组的长度的一半。
	思想就是:如果两个数不相等,就消去这两个数,最坏情况下,每次消去一个众数和一个非众数,那么如果存在众数,最后留下的数肯定是众数
思路1import java.util.*;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        Arrays.sort(array);
        return array[array.length/2];
    }
}
思路2import java.util.*;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
        for(int i=0;i<array.length;i++){
            if(map.containsKey(array[i])){
                map.put(array[i],map.get(array[i])+1);
            }else{
                map.put(array[i],1);
            }
        }
        for(Map.Entry<Integer,Integer> m:map.entrySet()){
            if(m.getValue()>array.length/2) return m.getKey();
        }
        return 0;
    }
}
思路3import java.util.*;
public class Solution {
    public int MoreThanHalfNum_Solution(int[] numbers) {
        int condatate=numbers[0];
        int count=1;
        for(int i=1;i<numbers.length;i++){
            if(numbers[i]==condatate){
                count++;
            }else{
                count--;
            }
            if(count==0){
                condatate=numbers[i+1];
            }
        }
        return condatate;
    }
}

NC74 数字在升序数组中出现的次数

思路1:
	遍历 空间复杂度:O(1),时间复杂度 O(n)
思路2:
	二分查找 找到k之后 判断left和right是否是k 是的话变动指针,不是的话right--;
	空间复杂度:O(1),时间复杂度 O(log(n))
思路1public class Solution {
    public int GetNumberOfK(int [] array , int k) {
        int count = 0;
        for(int e:array){
            if(k==e) count++;
        }
        return count;
    }
}
思路2public class Solution {
    public int GetNumberOfK(int [] array , int k) {
        int left=0;
	     int right=array.length-1;
	     int count=0;
	     while(left<=right&&left>=0&&right<=array.length-1){
	    	 int mid=(left+right)/2;
	    	 if(array[mid]>k){
	    		 right=mid-1;
	    	 }else if(array[mid]<k){
	    		 left=mid+1;
	    	 }else {
	    		if(array[left]==k){
	    			count+=(mid-left+1);
	    			left=mid+1;
	    		}else if(array[right]==k){
	    			count+=(right-mid+1);
	    		    right=mid-1;
	    		}else{
	    			right-=1;
	    		}	    		
	    	 }
	     }
	     return count;
    }
}

NC77 调整数组顺序使奇数位于偶数前面(一)

描述
输入一个长度为 n 整数数组,数组里面不含有相同的元素,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面部分,所有的偶数位于数组的后面部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

数据范围:0≤n≤5000,数组中每个数的值0≤val≤10000
要求:时间复杂度 O(n),空间复杂度 O(n)
进阶:时间复杂度 O(n^2),空间复杂度 O(1)

示例1
输入:[1,2,3,4]
返回值:[1,3,2,4]

示例2
输入:[2,4,6,5,7]
返回值:[5,7,2,4,6]

示例3
输入:[1,3,5,6,7]
返回值:[1,3,5,7,6]
思路1:
	插入排序 空间复杂度:O(1),时间复杂度 O(n^2)
思路2:
	重新new数组 空间复杂度:O(n),时间复杂度 O(n)
思路1import java.util.*;
public class Solution {
    public int[] reOrderArray (int[] array) {
        for(int i=0;i<array.length;i++){
            //找到一个奇数 开始插入排序
            if(array[i]%2==1){
                int index=i;
                while(index>0&&array[index-1]%2==0){
                    int temp=array[index];
                    array[index]=array[index-1];
                    array[index-1]=temp;
                    index--;
                }
            }
        }
        return array;
    }
}
思路2import java.util.*;
public class Solution {
    public int[] reOrderArray (int[] array) {
        if(array.length <= 1){
            return array;
        }
        int []res = new int[array.length];
        int index = 0;
        for(int i = 0; i < array.length; i ++){
            if((array[i] & 1) == 1 ){
                res[index ++] = array[i];
            }
        }
        for(int i = 0; i < array.length; i ++){
            if((array[i] & 1) == 0 ){
                res[index ++] = array[i];
            }
        }
        return res;
    }
}

NC83 子数组最大乘积

描述
给定一个double类型的数组arr,其中的元素可正可负可0,返回连续子数组累乘的最大乘积。

数据范围:数组大小满足0≤n≤10,数组中元素满足∣val∣≤10
进阶:空间复杂度 O(1),时间复杂度 O(n)

示例1
输入:[-2.5,4,0,3,0.5,8,-1]
返回值:12.00000
说明:取连续子数组[3,0.5,8]可得累乘的最大乘积为12.00000 

示例2
输入:[1.0,0.0,0.0]
返回值:1.00000
说明:取连续子数组[1.0]可得累乘的最大乘积为1.00000
思路:
	动态规划:
		max[i]=Math.max(num[i],num[i]*max[i-1],num[i]*min[i-1])
		min[i]=Math.min(num[i],num[i]*max[i-1],num[i]*min[i-1])
public class Solution {
    public double maxProduct(double[] nums) {
        double max = nums[0], min = nums[0];
        double res = nums[0];
        for (int i = 1; i < nums.length; ++i) {
            double m = max, n = min;
            max = Math.max(nums[i], Math.max(nums[i] * m, nums[i] * n));
            min = Math.min(nums[i], Math.min(nums[i] * m, nums[i] * n));
            res = Math.max(res, max);
        }
        return res;
    }
}

NC95 数组中的最长连续子序列

描述
给定无序数组arr,返回其中最长的连续序列的长度(要求值连续,位置可以不连续,例如 3,4,5,6为连续的自然数)
数据范围:1≤n≤10^5,数组中的值满足1≤val≤10^8
要求:空间复杂度 O(n),时间复杂度 O(nlogn)

示例1
输入:[100,4,200,1,3,2]
返回值:4
解释:1、2、3、4

示例2
输入:[1,1,1]
返回值:1
思路1:
	快速排序,在寻找连续的长度 空间复杂度 O(1),时间复杂度 O(nlogn)
import java.util.*;
public class Solution {
    public int MLS (int[] arr) {
        if(arr == null || arr.length==0)return -1;
        Arrays.sort(arr);
        int maxLen=1;
        int count=1;
        for(int i=1;i<arr.length;i++){
            if(arr[i]==arr[i-1]) continue;
            if(arr[i]-arr[i-1]==1){
                count++;
            }else{
                count=1;
            }
            maxLen=Math.max(maxLen,count);
        }
        return maxLen;
    }
}

NC106 三个数的最大乘积

描述
给定一个长度为 n 的无序数组 A ,包含正数、负数和 0 ,请从中找出3个数,使得乘积最大,返回这个乘积。
要求时间复杂度:O(n) ,空间复杂度:O(1) 

数据范围:3≤n≤10^4,-10^4≤A[i]≤10^4
 
示例1
输入:[3,4,1,2]
返回值:24
思路:三种情况:
	1 全是正数 :最大的三个数
	2 全是负数 : 最大的三个数
	3 一半正数 一半负数 : Math.max(最大的三个数9,最小的两个数*最大的数)
	时间复杂度:O(n) ,空间复杂度:O(1)
思路1import java.util.*;
public class Solution {
    public long solve (int[] A) {
        int max1= Integer.MIN_VALUE,max2= Integer.MIN_VALUE,max3= Integer.MIN_VALUE;
        int min1 = Integer.MAX_VALUE,min2 = Integer.MAX_VALUE;
        for(int num:A){
            if(num > max1){
                max3 = max2;
                max2 = max1;
                max1 = num;
            }else if(num > max2){
                max3 = max2;
                max2 = num;
            }else if(num > max3){
                max3 = num;
            }
            if(num < min1){
                min2 = min1;
                min1 = num;
            }else if(num < min2){
                min2 = num;
            }
        }
        return Math.max((long)max1*max2*max3,(long)max1*min1*min2);
    }
}

NC107 寻找峰值

描述
给定一个长度为n的数组nums,请你找到峰值并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个所在位置即可。
1.峰值元素是指其值严格大于左右相邻值的元素。严格大于即不能有等于
2.假设nums[-1]=nums[n]=−∞
3.对于所有有效的 i 都有 nums[i] != nums[i + 1]
4.你可以使用O(logN)的时间复杂度实现此问题吗?

示例1
输入:[2,4,1,2,7,8,4]
返回值:1
说明:4和8都是峰值元素,返回4的索引1或者8的索引5都可以  

示例2
输入:[1,2,3,1]
返回值:2
说明:3 是峰值元素,返回其索引 2
思路1:
	寻找大于左右元素的索引 时间复杂度:O(n),空间复杂度:O(1)
思路2:
	关键思想:下坡的时候可能找到波峰,但是可能找不到,一直向下走的  时间复杂度:O(log(n)),空间复杂度:O(1)
    上坡的时候一定能找到波峰,因为题目给出的是nums[-1] = nums[n] = -∞
思路1import java.util.*;
public class Solution {
    public int findPeakElement (int[] nums) {
        for(int i=1;i<nums.length-1;i++){
            if(nums[i]>nums[i-1]&&nums[i]>nums[i+1]) return i;
        }
        return nums[nums.length-1]>nums[0]?nums.length-1:0;
    }
}
思路2import java.util.*;
public class Solution {
    public int findPeakElement (int[] nums) {
        int left=0,right=nums.length-1;
        while(left<right){
            int mid=left+(right-left)/2;
            //证明右边的路是下坡路,不一定有坡峰
            if(nums[mid]>nums[mid+1]){
                right=mid;
            }else{
                //这里是右边的路是上坡路
                left=mid+1;
            }
        }
        return right;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CandyDingDing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值