1.平均数为k的最长连续子数组【有点难度,主要是这个思路是真没想起来】
题意理解:
求最长连续子序列,该子序列满足平均值为k的条件
解题思路:
1.双for循环遍历所有子串,但是超时了
2.第二种思路, 给所有的元素-平均数k,问题就变成了最长连续子序列,和为0,所以呢?然后相等还是遍历所有子串,和之前没有什么不同了,时间复杂度还是过不去。
3.第三种思路,借鉴大佬的思路,原来考的是前缀和+哈希表
哈希表里面存的值是索引,需要注意累加和sum需要用long
使用pre来记录前n个元素的和,map记录的是截止当前索引i下,元素和为cur
其实本质思路是:
第i个元素的时候求和sum=a, 第j个元素的时候求和sum=a则说明
(i,j]区间的元素和为0,故此处长度为0的子串长度为: j-i
1.解题思路
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Main solution=new Main();
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
int n = in.nextInt();
int k = in.nextInt();
int[] nums=new int[n];
for(int i=0;i<n;i++){
nums[i]=in.nextInt();
}
System.out.println(solution.compute(n,k,nums));
}
public int compute(int n,int k,int[] nums){
//记录结果
int maxLen=-1;
//前i个数的和
long pre=0;
Map<Long,Integer> map=new HashMap<>();
map.put(0L,0);
for(int i=0;i<n;i++){
//将avg=k的约束转换为sum=0
long cur=pre+nums[i]-k;
if(map.containsKey(cur)){
maxLen=Math.max(maxLen,i+1-map.get(cur));
}else{
map.put(cur,i+1);
}
pre=cur;
}
return maxLen;
}
}
2.复杂度分析
时间复杂度:O(n) for循环的存好
空间复杂度: O(2n) map的元素存储损耗
2.小球投盒【不难,但是可能出小问题】
题意理解:
有一堆盒子,两种操作:
操作1:往编号为i的元素中放一个球
操作2:除编号i的元素放一个球
操作到第几次时,所有盒子里都有小球
解题思路:
1.用一个list模拟盒子,进行操作,放过球,则将对应元素n移除list, 当前仅当list为空时,所有盒子有小球
2.考的是控制处理流程,不算难,但是容易超时
几个超时问题:
set.clear()会超时,但是set=new HashSet<>()不会,空间换时间的tips
1.解题
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Main main = new Main();
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int[][] opts = new int[m][2];
for (int i = 0; i < m; i++) {
opts[i][0] = in.nextInt();
opts[i][1] = in.nextInt();
}
System.out.println(main.commpute(n, m, opts));
}
public int commpute(int box, int optNum, int[][] opts) {
Set<Integer> set = new HashSet<>();
for(int i=1;i<=box;i++) set.add(i);
for(int i=1;i<=optNum;i++){
int target=opts[i-1][1];
//移除一个小球
if(opts[i-1][0]==1&&set.contains(target)){
set.remove( target);
}else if(opts[i-1][0]==2&&(!set.isEmpty())){
if(set.contains(target)){
set=new HashSet<>();
set.add(target);
}else{
set.clear();
}
}
if(set.isEmpty()){
return i;
}
}
return -1;
}
}
2.复杂度分析
时间复杂度:O(n) for循环遍历的时间损耗
空间复杂度:O(2n) 盒子的空间损耗+opts操作存储的空间损耗
3.小红结账【简单题】
题意理解:
共有n个账单,每次k个人吃饭,每次给小红的钱向上取整。
其中小红的朋友共m个,其中同一个朋友可能参与多次聚餐,需计算,每个人总共需要转给小红的账单。而不是某一个账单需要转的钱!
解题思路:
题目比较简单。使用payResult[m]维护结果,其中payResult[i]表示n个账单中,第i个朋友需给小红转的钱。
遍历账单,计算avg平均数
将平均数,加至指定朋友需付的钱中
返回结果
1.解题
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Main solution=new Main();
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int[][] costItem=new int[n][2];
String[] friends=new String[n];
for(int i=0;i<n;i++){
costItem[i][0]=in.nextInt();
costItem[i][1]=in.nextInt();
in.nextLine();
friends[i]=in.nextLine();
}
long[] payResult=solution.compute(n,m,costItem,friends);
for(long num:payResult){
System.out.print(num+" ");
}
}
public long[] compute(int n,int m,int[][] costItem,String[] friends){
long[] payResult=new long[m];
//遍历账单
for(int i=0;i<n;i++){
String[] num=friends[i].split(" ");
// System.out.println("S:"+friends[i]+" | "+num.length);
int payItem=(costItem[i][1]+num.length)/costItem[i][0];
// System.out.println("Avg:"+payItem);
for(int j=0;j<num.length;j++){
int index=Integer.valueOf(num[j])-1;
payResult[index]+=payItem;
}
}
return payResult;
}
}
2.复杂度分析
时间复杂度:O(O^2) 双for循环时间损耗
空间复杂度:O(2n) 账单存储损耗+结果数组存储损耗
4.小美的游戏【简单题】
题意理解:
有个n个元素的数组,将两个元素的ai,aj的乘积换成x,y的乘积,要使整个数组的总和尽可能的大。
解题思路:
为了使整个数组总和尽可能的大,就要使元素尽可能的大,最有效的一个方式如:
比如获得两个元素: 4*5=20*1 将元素4+5换成20+1,
所以,尽可能让两个大的元素相乘,并将其转换为1*乘积的两个元素,此时和最大
1.对数组排序,大数在数组后面
2.从后面进行遍历,每次将两个最大的数相乘,转换为1*乘积
3.总是把1放在后面(i),乘积常在前面(i-1)的位置,方便继续两个最大值的相乘。
4.最后求和
1.解题
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Main solution=new Main();
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int k = in.nextInt();
long[] nums=new long[n];
for(int i=0;i<n;i++){
nums[i]=in.nextLong();
}
System.out.println(solution.compute(n,k,nums));
}
public long compute(int n,int k,long[] nums){
long result=0;
Arrays.sort(nums);
for(int i=nums.length-1;i>=0;i--){
if(k>0&&i>0){
nums[i-1]=(long)(((nums[i]%(Math.pow(10,9)+7))*(nums[i-1]%(Math.pow(10,9)+7)))%(Math.pow(10,9)+7));
nums[i]=1;
k--;
}
result=(long)((result+nums[i])%(Math.pow(10,9)+7));
}
return result;
}
}
2.复杂度分析
时间复杂度:O(n) for循环的时间损耗
空间复杂度:O(n) nums数组的空间损耗
5.小美种果树 【简单题】
题意理解:
一个树成熟需要能量值z
每天浇水+x
每三天施肥+y
求累计几天,能量值到达z
解题思路:
比较简单,在合适的位置累加x,y,当前且仅当sum>=z时,跳出循环,树成熟
1.解题
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Main solution=new Main();
Scanner in = new Scanner(System.in);
int x = in.nextInt();
int y = in.nextInt();
int z = in.nextInt();
System.out.println(solution.compute(x,y,z));
}
public int compute(int x,int y,int z){
int sum=0;
int i=0;
while(sum<z){
sum+=x;
if(i%3==0){
sum+=y;
}
i++;
}
return i;
}
}
2.复杂度分析
时间复杂度:O(n) while循环的时间损耗
空间复杂度:O(1) 存储result的空间损耗
6.小美的数组重排【简单题】
题意理解:
两个数组,要求元素重排后,对应位置上的元素和满足[1,m]的条件限制
能满足该条件则输出Yes,负责输出No
共进行q次判断(询问)
解题思路:
对于数组a升序排列,数组b降序排列
检查对应位置是否满足值在[1,m]的约束,符合Yes,否则No
1.遍历q次询问
2.判断
3.输出结果
1.解题
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Main main=new Main();
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
int q=in.nextInt();
String[] result=new String[q];
for(int i=0;i<q;i++){
int n=in.nextInt();
int m=in.nextInt();
int[] a=new int[n];
int[] b=new int[n];
for(int j=0;j<n;j++){
a[j]=in.nextInt();
}
for(int j=0;j<n;j++){
b[j]=in.nextInt();
}
result[i]=main.compute(n,m,a,b);
}
for(String s:result){
System.out.println(s);
}
}
public String compute(int n,int m,int[] aArr,int[] bArr){
Arrays.sort(aArr);
Arrays.sort(bArr);
for(int i=0;i<n;i++){
if(aArr[i]+bArr[n-1-i]>m||aArr[i]+bArr[n-1-i]<1) return "No";
}
return "Yes";
}
}
2.复杂度分析
时间复杂度:O(nlogn) sort的时间损耗
空间复杂度:O(n) 以为数组存储元素的空间损耗
7.判断ip地址是否合法【不难但易错】
题意理解:
对于IP地址的判断
1.是否合法地址
2.是A\B\C哪类地址
解题思路:
题目比较好理解,但容易出错
需要注意的地方:
1. address.split("\\.")
当且仅当.在最后一位时:如1.2.3.4. 划分结果 1 2 3 4,但是其实是非法地址
当且仅当.在第一位时:如 .1.2.3.4 划分结果为 “” 1 2 3 4,非法地址
2.对于地址每部分,1.02.3.4 02是非法的表达
3.对于非. 非数组的部分存在时,也是非法表达
1.解题
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Main main=new Main();
Scanner in = new Scanner(System.in);
String address=in.nextLine();
boolean flag=true;
//元素检查
for(int i=0;i<address.length();i++){
if(address.charAt(i)!='.'&&(!Character.isDigit(address.charAt(i)))){
flag=false;
break;
}
if(address.charAt(i)=='.'&&i==address.length()-1){
flag=false;
}
}
//组成检查
if(flag==true){
String[] parts=address.split("\\.");
if(parts.length!=4) flag=false;
else{
for(String part:parts){
if("".equals(part.trim())){
flag=false;
break;
}
if(part.length()>=2&&part.startsWith("0")){
flag=false;
break;
}
}
}
}
if(flag==false){
System.out.println("invalid");
}else{
System.out.println(main.compute(address));
}
}
public String compute(String addressStr){
String result="";
String[] address=addressStr.split("\\.");
int part1=Integer.valueOf(address[0]);
int part2=Integer.valueOf(address[1]);
int part3=Integer.valueOf(address[2]);
int part4=Integer.valueOf(address[3]);
if(part1<0||part1>255||part2<0||part2>255||part3<0||part3>255||part4<0||part4>255) result="invalid";
else if(part1<=125&&part1>=1){
result="A_address";
}else if(part1==126&&part2==0&&part3==0&&part4==0){
result="A_address";
}else if(part1<=191&&part1>=128){
result="B_address";
}else if(part1<=223&&part1>=192){
result="C_address";
}else {
result="other";
}
return result;
}
}
2.复杂度分析
时间复杂度:O(n) for循环时间损耗
空间复杂度:O(1) 结果result空间损耗