一、排序篇:Java中的sort函数
package practice;
import java.util.*;
public class Main {
public static void main(String[] args) {
int[] a= {7, 3, 6, 2, 4, 5, 9};
Arrays.sort(a);//对数组进行排序
for(int num:a) {
System.out.print(num+" ");//升序
}
System.out.println();
for(int i=a.length-1;i>=0;i--) {
System.out.print(a[i]+" ");//降序
}
}
}
练习1:拼数
直接整数排序肯定不对。。。。
不能用单纯的字符串排序,这样不能达到最大,因为默认中前缀相同时,短<长
import java.util.Scanner;
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n=scan.nextInt();
String[] a=new String[n];
for(int i=0;i<n;i++){
a[i]=scan.next();//遇到空格就停,不能自己换行
}
Arrays.sort(a,(x,y)->{ return (x+y).compareTo(y+x);});//Arrays.sort是从小到大排序的,后面只是给了个比较的法则
for(int i=n-1;i>=0;i--){//从大到小输出出来
System.out.print(a[i]);
}
scan.close();
}
}
或者将lamada公式换成冒泡排序:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] nums = new int[n];
for(int i = 0; i < n; i++)
nums[i] = sc.nextInt();
String[] s = new String[n];
String ans = "";
for(int i = 0; i < n; i++)
s[i] = nums[i] + "";
for(int i=1;i<=n-1;i++){
for(int j=0;j<n-i;j++){
if((s[j]+s[j+1]).compareTo(s[j+1]+s[j])<0){
String tmp=s[j];
s[j]=s[j+1];
s[j+1]=tmp;
}
}
}
for(int i = 0; i < n; i++)
ans += s[i];
System.out.println(ans);
}
}
练习二:错误票据
//package practice;
import java.util.*;
//1:无需package
//2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
ArrayList<Integer> list=new ArrayList<Integer>();
int n=scan.nextInt();
scan.nextLine();
for(int i=0;i<n;i++) {
String s=scan.nextLine();
String[] sarr=s.split(" ");
for(int j=0;j<sarr.length;j++) {
list.add(Integer.valueOf(sarr[j]));
}
}
Collections.sort(list);
int duan=0,chong=0;
for(int i=0;i<list.size()-1;i++){
if((list.get(i+1)-list.get(i))==2){
duan=list.get(i)+1;
}else if(list.get(i).equals(list.get(i+1))){
chong=list.get(i);
}
}
System.out.println(duan+" "+chong);
scan.close();
}
}
练习三、奖学金
主要是注意里面TreeSet排序算法的重写!!!!
package practice;
import java.util.*;
//1:无需package
//2: 类名必须Main, 不可修改
//重点在于重写比较器
public class Main {
public static class Grade{
//只关注有用的三个
private int num;
private int chinese;
private int Grade;
Grade(int num,int chinese,int Grade){//注意单词一定不能拼错
this.num=num;
this.chinese=chinese;
this.Grade=Grade;
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n=scan.nextInt();
scan.nextLine();//必须的
Set<Grade> set=new TreeSet<>(new Comparator<Grade>(){
public int compare(Grade a,Grade b){
if(a.Grade!=b.Grade){
return b.Grade-a.Grade;
}else if(a.chinese!=b.chinese){
return b.chinese-a.chinese;
}else{
return a.num-b.num;//注意有的地方不是倒序!!!!!
}
}
});
for(int i=1;i<=n;i++){
String[] sarr=scan.nextLine().split(" ");
int chinese=Integer.valueOf(sarr[0]);
int sum=Integer.valueOf(sarr[0])+Integer.valueOf(sarr[1])+Integer.valueOf(sarr[2]);
set.add(new Grade(i,chinese,sum));
}
int cot=0;
for(Grade grade:set){
System.out.println(grade.num+" "+grade.Grade);
cot++;
if(cot==5){
break;
}
}
scan.close();
}
}
练习四:外卖店优先级
注意Comparable类的继承,以及compareTo方法的改写
注意处理方式,先考虑输入的订单列表,然后再考虑剩下的
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static class My implements Comparable<My>{
int t,id;
My(int t,int id){
this.t=t;
this.id=id;
}
public int compareTo(My m){
if(t==m.t){
if(id>m.id){
return 1;
}else if(id<m.id){
return -1;
}else{
return 0;
}
}
return t > m.t ? 1 : -1;
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n=scan.nextInt();
int m=scan.nextInt();
int T=scan.nextInt();
int[] s=new int[n+1];//存放每个店铺当前的优先值
int[] pre=new int[n+1];//存放该id上一次有订单的时间
boolean[] st=new boolean[n+1];
My[] me =new My[m];
for(int i=0;i<m;i++){
int t=scan.nextInt();
int id=scan.nextInt();
me[i]=new My(t,id);
}
Arrays.sort(me);
for(int i=0;i<m;){
int j=i;
//同一小时内重复送往一家的情况,为了计数
while(j<m&&me[i].t==me[j].t&&me[i].id==me[j].id){
j++;
}
int id=me[i].id,t=me[i].t,cnt=j-i;//cnt表示这一小时送的订单数
i=j;
s[id] -= t-pre[id]-1;//-1是因为最近的这一小时是有订单的
if(s[id]<0) s[id]=0;
if(s[id]<=3) st[id]=false;
//注意这里的顺序,因为在等于零的情况下是不用减的,如果这个放前面则少算
s[id]+=cnt*2;
if(s[id]>5) st[id]=true;
pre[id]=t;//存放这次出现订单的时间
}
for(int i=1;i<=n;i++){
if(pre[i]<T){
s[i] -=T-pre[i];
if(s[i]<=3) st[i]=false;//因为这个循环中都是减少的,不会有超过5的
}
}
int res=0;
for(int i=1;i<=n;i++){
if(st[i]){
res++;
}
}
scan.close();
System.out.println(res);
}
}
二、排列篇
全排列,java中没有提供函数,只能手写555
方法一:递归:
下面的排列依然用的是递归的思想
递归需要满足两个条件:
1. 该问题可以转化为更小的子问题,且两者解决办法相同。
2. 有出口,该出口通常就是最小的子问题(不可再分)的解决办法。
故该问题中,若要对n个子母进行全排列,可以看作将将某一个子母放在第一位固定,对后面的n-1个字母再进行全排列,满足第一个条件。在只有一个字母的时候可以直接输出,这是最小的问题,也是出口,满足第二个条件。
package practice;
import java.util.*;
public class Main {
public static void permutation(char[] s,int from,int to) {
if(to<=1) {
return;
}
if(from==to) {
System.out.println(s);
}else {
//用到递归思想
for(int i=from;i<=to;i++) {
swap(s,i,from);
permutation(s,from+1,to);
swap(s,from,i);//将前缀撤回,继续做上一个全追的排序
}
}
}
public static void swap(char[] s,int i,int j) {
char tmp=s[i];
s[i]=s[j];
s[j]=tmp;
}
public static void main(String[] args) {
char[] s= {'a','b','c'};
permutation(s,0,2); //permutation(数组,头,尾) 不包括尾
}
}
方法二:字典序
如果当前排列是124653,找它的下一个排列的方法是,从这个序列中从右至左找第一个左邻小于右邻的数。如果找不到,则所有排列求解完成,如果找到则说明排列未完成。
本例中将找到46,计4所在的位置为i,找到后不能直接将4与6对换,而是要从右向左找第一个比4大的数,本例找到的是5,将其位置记为j,将i与j的位置交换,得到125643,然后将第i+1到最后一个元素从小到大排序的到125346,这就是124653的下一个排列:
public static boolean nextPermution(char[] data) {
int end=data.length-1;//从最右面开始
int swapPoint1=end,swapPoint2=end;
while(swapPoint1>0&&data[swapPoint1]<=data[swapPoint1]-1) {
swapPoint1--;
}
if(swapPoint1==0) {
return false;//已经没有后序了
}else {
//要替换的定位在swapPoint1-1:第一个不满足升序的
while(swapPoint2>0 && data[swapPoint2]<=data[swapPoint1-1]) {
swapPoint2--;
}
swap(data,swapPoint1-1,swapPoint2);
reverse(data,swapPoint1,end);//翻转,使后面几位的值最小
return true;
}
}
public static void swap(char[] data,int left,int right) {
char temp=data[left];
data[left]=data[right];
data[right]=temp;
}
public static void reverse(char[] data,int left,int right) {
for(int i=left,j=right;i<j;i++,j--) {
swap(data,i,j);
}
}
例题1:
【pk复试上机】
首先是常规的递归,将问题分解为第一个数和后面n-1个数,解决n个数的排序就是解决其后面n-1个数的排序问题。如果只剩下最后一个数则直接输出,即递归出口。 另外题目要求按照从小多大的顺序输出,则需要借助TreeMap进行排序,在JAVA中HashMap只有去重功能,不能排序。
import java.util.*;
import java.util.TreeMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class Main{
static Map<String,Integer> map=new TreeMap<String,Integer>();//进行排序
public static void permutation(char[] s,int from,int to){
if(to<1){
System.out.println(s);
return;
}
if(from==to){//只剩下一个的情况
String S=String.copyValueOf(s);
map.put(S,1);
}else{
for(int i=from;i<=to;i++){
swap(s,from,i);
permutation(s,from+1,to); //递归进行后面数字的排列
swap(s,from,i);//每一层都换回来,保证顺序不会被打乱
}
}
}
public static void swap(char[] s,int a,int b){
char tmp=s[a];
s[a]=s[b];
s[b]=tmp;
}
public static void main(String[] args){
Scanner in=new Scanner(System.in);
char[] s=in.nextLine().toCharArray();
permutation(s,0,s.length-1);
for(Entry<String,Integer> entry: map.entrySet()){
System.out.println(entry.getKey());
}
}
}
练习2:外星人
我的代码,非常繁琐。。。。超时了:
package practice;
import java.util.*;
//1:无需package
//2: 类名必须Main, 不可修改
public class Main {
public static int M=0;
public static Map<String,Integer> m=new TreeMap<String,Integer>();
public static String s;
public static boolean exit=false;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int N=scan.nextInt();
M=scan.nextInt();
scan.nextLine();
String[] a=scan.nextLine().split(" ");
StringBuffer sb2=new StringBuffer();
for(int i=0;i<a.length;i++) {
sb2.append(a[i]);
}
s=sb2.toString();
permution(a,0,a.length-1);
String ans="";
for(String c:m.keySet()) {
if(exit) {
M--;
if(M==0) {
ans=c;
break;
}
}
if(c.equals(s)) {
exit=true;
}
}
char[] C=ans.toCharArray();
for(int i=0;i<C.length;i++){
System.out.print(C[i]+" ");
}
scan.close();
}
public static void permution(String[] a,int from,int to) {
if(from==to) {
StringBuffer sb=new StringBuffer();
for(int i=0;i<a.length;i++) {
sb.append(a[i]);
}
String tmp=sb.toString();
m.put(tmp,1);
return;//注意返回
}
for(int i=0;i<a.length;i++) {
swap(a,from,i);
permution(a,from+1,to);
swap(a,from,i); //再换回来 防止重复
}
return;
}
public static void swap(String[] a,int i,int j) {
String tmp=a[i];
a[i]=a[j];
a[j]=tmp;
}
}
换用字典序的方法吧,碰上全排列java真的太卑微了呜呜呜~:
下面方法不超时,单说结果有误
package practice;
import java.util.*;
//1:无需package
//2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int N=scan.nextInt();
int M=scan.nextInt();
scan.nextLine();
String[] a=scan.nextLine().split(" ");
while(nextPermution(a)) {
M--;
if(M==0) {
break;
}
}
for(int i=0;i<a.length;i++) {
System.out.print(a[i]+" ");
}
scan.close();
}
public static boolean nextPermution(String[] data) {
int end=data.length-1;//从最右面开始
int swapPoint1=end,swapPoint2=end;
while(swapPoint1>0&&data[swapPoint1].compareTo(data[swapPoint1-1])<0) {
swapPoint1--;
}
if(swapPoint1==0) {
return false;//已经没有后序了
}else {
//要替换的定位在swapPoint1-1:第一个不满足升序的
while(swapPoint2>0 && data[swapPoint2].compareTo(data[swapPoint1-1])<0) {
swapPoint2--;
}
swap(data,swapPoint1-1,swapPoint2);
reverse(data,swapPoint1,end);//翻转,使后面几位的值最小
}
return true;
}
public static void swap(String[] data,int left,int right) {
String temp=data[left];
data[left]=data[right];
data[right]=temp;
}
public static void reverse(String[] data,int left,int right) {
for(int i=left,j=right;i<j;i++,j--) {
swap(data,i,j);
}
}
}
练习三:排列序数
package practice;
import java.util.*;
//1:无需package
//2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
char[] in=scan.nextLine().toCharArray();//细心没有空格 不能用空格来分
char[] temp=new char[in.length];
for(int i=0;i<in.length;i++) {
temp[i]=in[i];
}
Arrays.sort(temp);
int cnt=0;
boolean ok=true;
do {
for(int i=0;i<in.length;i++) {
if(temp[i]!=in[i]) {
ok=false;
break;
}
}
if(ok) {
System.out.println(cnt);
return;
}else {
ok=true;
}
cnt++;
}while(nextPermution(temp));
scan.close();
}
public static boolean nextPermution(char[] data) {
int end=data.length-1;
int swap1=end,swap2=end;
while(swap1>0 && data[swap1]<data[swap1-1]) {
swap1--;
}
if(swap1==0) {
return false; //已经是最大的 没有下一个
}else {
while(swap2>0 && data[swap2]<data[swap1-1]) {
swap2--;
}
swap(data,swap2,swap1-1);
reverse(data,swap1,end); //翻转 保证后面变动的范围值最小
}
return true;
}
public static void swap(char[] data,int left,int right) {
char temp=data[left];
data[left]=data[right];
data[right]=temp;
}
public static void reverse(char[] data,int left,int right) {
for(int i=left,j=right;i<j;i++,j--) {
swap(data,i,j);
}
}
}
练习四:带分数
package practice;
import java.util.*;
//1:无需package
//2: 类名必须Main, 不可修改
//带分数
//从最小的进行全排列
//然后进行划分,但是第一个最多只有三位,需要比较一下和100的大小
//剩下的从中间位置往后,知道相除的整数 再看加起来得不得100
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int sum=scan.nextInt();
int[] data=new int[9];
for(int i=1;i<10;i++) {
data[i-1]=i;
}
int ans=0;
do {
for(int i=0;i<7;i++) {
int rest=sum-toData(data,0,i); //去掉第一个数之后剩下的
if(rest<=0) {
break;//已经不能再增加了
}
for(int j=(i+1+8)/2;j<8;j++) {
if(toData(data,i+1,j)%toData(data,j+1,8)==0) {
if(toData(data,i+1,j)/toData(data,j+1,8)==rest) {
ans++;
break;//这种情况下只有一个对应的答案,所以找到之后可以直接break出内循环
}
}
}
}
}while(nextPermution(data));
System.out.println(ans);
scan.close();
}
public static boolean nextPermution(int[] data) {
int end=data.length-1;
int swap1=end,swap2=end;
while(swap1>0 && data[swap1]<data[swap1-1]) {
swap1--;
}
if(swap1==0) {
return false; //已经是最大的 没有下一个
}else {
while(swap2>0 && data[swap2]<data[swap1-1]) {
swap2--;
}
swap(data,swap2,swap1-1);
reverse(data,swap1,end); //翻转 保证后面变动的范围值最小
}
return true;
}
public static void swap(int[] data,int left,int right) {
int temp=data[left];
data[left]=data[right];
data[right]=temp;
}
public static void reverse(int[] data,int left,int right) {
for(int i=left,j=right;i<j;i++,j--) {
swap(data,i,j);
}
}
public static int toData(int[] data,int begin,int end) {
int ans=0;
int n=1;
if(end==begin) {
return data[begin];
}
for(int i=end;i>=begin;i--) {
ans+=n*data[i];
n=n*10;
}
return ans;
}
}
练习五:第几个幸运数
方法一:暴力解法,直接循环,注意有一个零的值,所以范围不能等于59084709587505
# 用python直接暴力
import os
import sys
# 请在此输入您的代码
cnt=0
for i in range(50):
for j in range(50):
for k in range(50):
a=3**i
b=5**j
c=7**k
if a*b*c < 59084709587505: #不等于是因为多出来一个零的情况
cnt=cnt+1
print(cnt)
//java暴力,注意大数使用long
import java.util.*;
//第几个幸运数字
public class Main {
public static void main(String[] args) {
int cnt=0;
long n=59084709587505L;//记得在末尾加上L
for(int i=0;Math.pow(3,i)<59084709587505L;i++) {
for(int j=0;Math.pow(5, j)<59084709587505L;j++) {
for(int k=0;Math.pow(7, k)<59084709587505L;k++) {
if(Math.pow(3,i)*Math.pow(5, j)*Math.pow(7, k)<59084709587505L)
cnt++;
}
}
}
System.out.println(cnt);
}
方法二:优先队列+set去重
优先队列:PriorityQueue<Long> q=new PriorityQueue<Long>(); 总是返回队列中的最小值,实现原理是小顶堆
用Hashset进行去重,用优先队列保证每次取出的都是最小的,然后依次乘上3、5、7符合要求的话就放在优先队列和set里面,要注意去重
package practice;
import java.util.PriorityQueue;
import java.util.*;
//优先队列+set去重
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
long n=59084709587505L;//注意加上L
long t=n;
//优先队列,总是返回有限队列中的最小值
PriorityQueue<Long> q=new PriorityQueue<Long>();
//去重
Set<Long> st=new HashSet<Long>();
//将3、5、7放在num数组中
long[] num={3,5,7};
//加上最小的三个数
for(int i=0;i<3;i++){
q.add(num[i]);
st.add(num[i]);
}
int cnt=0;
//等于说从小到大的找,减少循环的次数
while(q.isEmpty()==false){
long h=q.poll();//返回最小的元素
++cnt; //出来一个就加上
if(h==n) break; //已经到了n
for(int i=0;i<3;i++){
t=h*num[i];
if(t>n) continue; //如果大于的话就略过,保证都是小雨的
if(st.contains(t)==false){
q.add(t);
st.add(t);
}
}
}
System.out.println(cnt);
scan.close();
}
}