本博客文章(学习笔记)导航 (点击这里访问)
描述
以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。
数据范围: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();
}
}
描述
假设你有一个数组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:
动态规划
当天持有股票:前天持有股票或者今天刚买
当天不持有股票:前天不持有股票或者前天持有今天刚卖
思路1:
import 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;
}
}
思路2:
import 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];
}
}
描述
给定节点数为 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;
}
}
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;
}
}
描述
给出一个有序的整数数组 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];
}
}
}
}
描述
现在有一个没有重复元素的整数集合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);
}
}
描述
在一个二维数组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);
}
}
}
描述
给定一个无重复元素的整数数组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)
思路1:
import 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;
}
}
思路2:
import 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;
}
}
描述
给定两个递增数组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;
}
}
描述:给出一组区间,请合并所有重叠的区间。请保证合并后的区间按区间起点升序排列。
数据范围:区间组数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;
}
}
示例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;
}
}
示例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;
}
}
要求:空间复杂度 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;
}
}
空间复杂度: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;
}
}
给定一个n*m 的矩阵 a,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,输出所有的路径中最小的路径和。
数据范围:0
思路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)
思路1:
public class Solution {
public int Fibonacci(int n) {
if(n==1||n==2) return 1;
return Fibonacci(n-1)+Fibonacci(n-2);
}
}
思路2:
public 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];
}
}
思路3:
public 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:
候选法:
加入数组中存在众数,那么众数一定大于数组的长度的一半。
思想就是:如果两个数不相等,就消去这两个数,最坏情况下,每次消去一个众数和一个非众数,那么如果存在众数,最后留下的数肯定是众数
思路1:
import java.util.*;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
Arrays.sort(array);
return array[array.length/2];
}
}
思路2:
import 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;
}
}
思路3:
import 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))
思路1:
public class Solution {
public int GetNumberOfK(int [] array , int k) {
int count = 0;
for(int e:array){
if(k==e) count++;
}
return count;
}
}
思路2:
public 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)
思路1:
import 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;
}
}
思路2:
import 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)
思路1:
import 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] = -∞
思路1:
import 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;
}
}
思路2:
import 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;
}
}
你可能感兴趣的:(算法,数据结构)