5道算法题,俩小时
1、奖学金人数
n个学生,m个科目。已知每个学生的分数。给学生发单科奖学金,取每科最高分的同学(可能并列,都发)发奖学金。问一共有多少同学得到了奖学金?
分析
- 这个全通过了,思路比较简单,统计每科最高分,给分数为最高的同学发奖。
public static int meituan1(){
Scanner sc = new Scanner(System.in);
//学生人数
int n = sc.nextInt();
//考试科目数
int m = sc.nextInt();
int [][] score = new int [n][m];
//第i学生
for (int i = 0; i < score.length; i++) {
//第j科目
for (int j = 0; j < score[i].length; j++) {
score[i][j] = sc.nextInt();
}
}
//记录学生是否是最好
boolean best [] = new boolean[n];
//查看每一科 最好的
for (int j = 0; j < m; j++) {
int bestScore = 0;
//每一个学生
for(int i = 0; i <n;i++){
if(score[i][j] > bestScore){
bestScore = score[i][j];
}
}
for(int i = 0;i <n ;i++){
if(score[i][j] == bestScore){
best[i] = true;
}
}
}
int sum = 0;
for (int i = 0; i < best.length; i++) {
if(best[i]){
sum++;
}
}
System.out.println();
return sum;
}
2、最小循环节
给定 a b m x 按照公式迭代计算 x=(a*x+b)%m;
x会产生循环序列,问最小的循环序列长度。
分析
- 感觉思路不太对,只过了一半的测试
- 用map,每一个x值,作为key。
public static void meituan2(){
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
int m = sc.nextInt();
int x= sc.nextInt();
HashMap<Integer,Integer> map = new HashMap<>();
while (true){
x=(a*x+b)%m;
if (map.containsKey(x)){
map.put(x,map.get(x)+1);
}else{
map.put(x,1);
}
if(map.get(x) >2){break;}
}
System.out.println(map.size());
}
3、第k小的坐标
a1 = (x1,y1)与a2=(x2,y2)比较。
x1>x2 则 a1 >a2
x1 < x2 则 a1 < a2
如果x1 == x2,比较y,给出结论。
给出n个数,(x,y)都可以取n中的任意一个数,求第k小坐标。
分析
- 想出了一个比较智障的算法,通过了一半的样子,提示是超时。。。。。。。
- 生成所有的坐标,按规则排序,找出第k小。
- 隐隐约约感觉不对,是不是有更简单的法子。事后诸葛亮想了想,还真是有。先将输入的n个数排序,用两层循环,分别对x,y取值,因为是排序好的,循环取数时候,坐标也是递增的,计数到k就行了。。。。。。。。。。。
不太行的写法
public static void meituan3(){
ArrayList<Pair> list = new ArrayList<>();
Scanner sc = new Scanner(System.in);
//多少个数
int nums = sc.nextInt();
//第k小
int k = sc.nextInt();
int data [] = new int [nums];
for (int i = 0; i < data.length; i++) {
data[i] = sc.nextInt();
}
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data.length; j++) {
list.add(new Pair(data[i],data[j]));
}
}
list.sort(new Comparator<Pair>() {
@Override
public int compare(Pair p1, Pair p2) {
if(p1.x > p2.x){
return 1;
}else if(p1.x < p2.x){
return -1;
}else{
// ==
if(p1.y > p2.y){
return 1;
}else if(p1.y < p2.y){
return -1;
}else{
return 0;
}
}
}
});
System.out.println(list.get(k-1));
}
事后诸葛亮法
public static void meituan3Improve(){
Scanner sc = new Scanner(System.in);
//多少个数
int nums = sc.nextInt();
//第k小
int k = sc.nextInt();
int data [] = new int [nums];
for (int i = 0; i < data.length; i++) {
data[i] = sc.nextInt();
}
Arrays.sort(data);
int count = 0;
int x= 0;
int y = 0;
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data.length; j++) {
count++;
if(count == k){
x= i;
y = j;
break;
}
}
}
System.out.println("("+x+","+y+")");
}
4、伪中位数
给出n,k。n代表后续有n个数,参与排序。这n个数定义中位数,对于排序好的数组,i=(1+n)/2 并向下取整,第i个数就是伪中位数。
k表示数组中的一个数。
想让在该数组中为k的数成为伪中位数,在数组应该至少要插入多少元素?
如 4 2
2 3 3 3
一共四个数 想让2成为中位数,要在2之前插入比2小的数1 1,2就是中位数了。此时返回2,因为插入了两个1。
分析
- 经过验证,伪中位数,就是如果n是奇数,就是正中央的数,如果是偶数个数,就是左半边最后一个数。
- 将数组排序,计算中位数所在的下标mid。
- 找出k所在下标j。
- 如果两下标相等,不用插入元素。
- 如果j < mid。说明j左边需要插入元素。计算j右边的元素个数,n-1-j,计算j左边元素个数 j。右边比左边多的元素,如果插入元素,使j左右元素个数相等,j就处在中位数位置,但是少插入一个也可以,就是总数是偶数的情况。所以n -1-j-j - 1;
- 反之,j>mid。j - (n-1-j) -1;
- 但是很失望,也是没有全部通过!!!!!
public static void meituan4(){
Scanner sc = new Scanner(System.in);
//多少个数
int n = sc.nextInt();
int data [] = new int [n];
//目标数 使k成为中位数
int k = sc.nextInt();
for (int i = 0; i < data.length; i++) {
data[i] = sc.nextInt();
}
Arrays.sort(data);
//j 是k所在位置
int j = 0;
for (j = 0; j < data.length; j++) {
if(data[j] == k){
break;
}
}
int mid = getMidPos(data);
int res = 0;
if(mid == j){
res = 0;
}else if(j < mid){
// n-1-j j右边有几个 j就是j左边有几个 j左右边数目相同 还要减1
res = n -1-j-j - 1;
}else{
res = j - (n-1-j) -1;
}
System.out.println(res);
}