题目描述
YJC最近在steam.上氪了不少金,但他还想氪更多。steam保证了不同的两款游戏的价格一定不同,并且游戏的价格- - 定是正整数。现在YJC已经买下了n款不同的游戏,价格分别为a1、a2、 .... an。 YJC手头还有m元,他想知道他最多还能入手多少款他没有的游戏?
输入
第一行包含两个整数n和m,表示YJC已经买下的游戏数和YJC的钱数。
第二行包含n个整数a,表示YJC已经入手的每一款游戏。
输出
第一行包含-一个整数k,表示YJC最多还能买下多少款游戏。
第二行包含k个整数b,表示YJC接下来要买下的每一款游戏。 如果有多组解,输出
字典序最小的。
样例输入
4 14
4 6 8 12
样例输出
4
1 2 3 5
提示
对于100%的数据,满足1<=n<=10的5次,1<=m,ai<,10的9次。
题目的出处是啥?
正睿oi
类似这样?
private static void gameCnt(int n, int m, Integer[] mArr) {
System.out.println("n:" + n + ", m:" + m + "mArr:" + Arrays.toString(mArr));
if(null == mArr || n < 0 || n != mArr.length){
System.out.println("fail");
return;
}
List<Integer> ml = Arrays.asList(mArr);
int i = 1;
List<Integer> wm = new ArrayList<>();
while(m > 0 && m >= i){
if(!ml.contains(i)){
wm.add(i);
m = m - i;
}
i++;
}
System.out.println(wm);
}
谢谢
文字很长,核心重点:两款游戏的价格一定不同且价格一定是正整数。
所以整个题目可以简单化为:YJC 有一个整数列表x和一个整数m。从正整数a=1开始逐渐+1遍历,如果不在列表x中,则加入返回列表y中,且m-a。
实现如下:
[Theory]
[InlineData(new int[] { 4, 6, 8, 12 }, 14, 4)]
public void SampleTest(int[] owned, int money, int expectBuyCount)
{
int price = 1; //游戏价格
int count = 0; //可买数量
List<int> buy = new List<int>(); //可买游戏价格表
while (money > 0)
{
//钱不够了
if (money < price)
{
break;
}
//已经买过了
if (owned.Contains(price))
{
price++;
continue;
}
//买下游戏
money = money - price;
buy.Add(price);
price++;
count++;
}
Assert.True(expectBuyCount == count);
}
优化点:
每次都要去owned列表中去判断存不存在,考虑优化
1.把owned列表转为hash表,这样每次判断o(1)的时间复杂度
2.如果owned列表是有序的,可以遍历owned列表,然后每次遍历owned列表i和i+1之间的整数,即为可买的数
全部遍历是可以,但是肯定有更好的办法,这个程序,我觉写的好的话没半天功夫搞不定,搞不好需要1天甚至更多。
首先给定了钱数,可以先算最多可以分多少组,这样就会省下很多遍循环,可以通过计算从1加到n的和是小于m的最大值时的n作为最多可以分的组数
然后在分的时候还可以加一些判断减少循环,比如,如果要买3个游戏,总钱数是m,当这3个游戏里最低的价格高于m的1/3时就不用看后面的了
简单写了一下,能得到题主解。只是要多组解的话估计用上hashmap就行
代码如下:
public class Test09 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
ArrayList<Integer> al = new ArrayList(); //用一个数组来装已买的各种游戏的价钱
for (int i = 0; i < n; i++) {
al.add(sc.nextInt());
}
ArrayList<String> bl = new ArrayList(); //用另一个数组来装还能买的游戏价钱
int sum = 0;
int count = 0;
loop: for (int i = 1; ; i++) {
if (al.contains(i)) { //如果该价钱已经买了则直接跳过,继续循环
continue;
} else {
sum += i;
count ++;
bl.add(i+""); //将价钱添加到数组前先转换为字符串,方便打印,避免打印时与索引冲突
if (sum > m) { //如果总价钱超了,把最后一个游戏退回去,然后跳出整个循环
sum -= i;
count --;
bl.remove(i+"");
break loop;
}
}
}
System.out.println(bl.size());
for (int i = 0; i < bl.size(); i++) {
System.out.print(bl.get(i) + " ");
}
}
}