辗转相除法:
int GCD(int a,int b)
{
if(a%b==0) return b;
//如果a%b==0 代表可以被整除,那么b就是最大公约数
else return GCD(b,a%b)
// 如果不能被整除,那么就先取余数,代码会保证左侧是大的,右侧是小的数字,所以使用时不必进行大小检查,即使a<b也会再一次递归后变成b,a在进行计算。
//这样就能按照辗转相除法求解。(小学五年级的课程吧)
}
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
public class Main {
static int check(int a, int b, int c)
{
int flag[]=new int[11];
for(int i=0;i<10;i++) flag[i]=0;
flag[0]=1;
while(a!=0)
{
if(flag[a%10]==1) return 0;
else flag[a%10]=1;
if(flag[b%10]==1) return 0;
else flag[b%10]=1 ;
if(flag[c%10]==1) return 0;
else flag[c%10]=1 ;
a=a/10;
b=b/10;
c=c/10;
}
return 1;
}
public static void main(String[] args) {
int ans=0;
for(int a=123;a<=987;a++)
for(int b=123;b<=987-a;b++)
{
int c=a+b;
if(check(a,b,c)==1)
{
ans++;
System.out.println(a+"+"+b+"="+c);
}
}
System.out.println(ans);
}
}
栈
import java.util.Scanner;
import java.util.Stack;
public class Main {
static Stack Mystack =new Stack();
public static void main(String[] args)
{
int N;
Scanner in=new Scanner(System.in);
N=in.nextInt();
for(int i=0;i<N;i++)
{
String op,name;
op=in.next();
name=in.next();
// System.out.println(op+" "+name);
if(op.contains("in") )
Mystack.push(name);
else {
while(!Mystack.peek().equals(name)){
// System.out.println(getTop());
Mystack.pop();
}
Mystack.pop();
}
}
if(Mystack.empty()) System.out.println("Empty");
else System.out.println(Mystack.peek());
}
}
哈希表
import java.util.Scanner;
import java.util.Stack;
public class Main {
static final int h=999983;
static String[] Value=new String [h];
static String[] UpValue=new String [h];
static int UpValueCount=0;
static int Hx(String s) {
return (s.hashCode()%h+h)%h;
}
static boolean isAt(String s)
{
int n=Hx(s);
if(Value[n]==null) return false;
else if(Value[n].equals(s)) return true;
else {
for(int i=0;i<UpValueCount;i++)
if(UpValue[i].equals(s)) return true;
return false;
}
}
static boolean in(String s)
{
int n=Hx(s);
if(Value[n]==null) {
Value[n]=s;
return true;
}
else if(Value[n].equals(s)) return false;
else {
for(int i=0;i<UpValueCount;i++)
if(UpValue[i].equals(s)) return false;
UpValue[UpValueCount++]=s;
return true;
}
}
public static void main(String[] args)
{
int n;
boolean flag=false;
Scanner in=new Scanner(System.in);
String ans="NO";
n=in.nextInt();
for(int i=0;i<n;i++)
{
String word;
word=in.next();
// System.out.println(Hx(word));
if(flag) continue;
if(isAt(word)){
flag=true;
ans=word;
}
else {
in(word);
}
}
System.out.println(ans);
}
}
sort排序
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
public static class MyComparator implements Comparator<Long> {
@Override
public int compare(Long a, Long b) {
return a==b ? 0 : (a > b ? 1 : -1);
}
}
public static void main(String[] args) {
Long[] arr = new Long[500005];
int n;
Scanner in=new Scanner(System.in);
n=in.nextInt();
for(int i=0;i<n;i++)
{
arr[i]=in.nextLong();
}
Comparator<Long> cmp = new MyComparator();
Arrays.sort(arr, 0,n,cmp); //也可以缺省cmp
for (int i =0;i<n;i++){
System.out.print(arr[i] + " ");
}
System.out.println("");
for (int i = n-1; i >=0; i--)
{
System.out.print(arr[i]+" ");
}
}
}
Vector
import java.util.List;
import java.util.Scanner;
import java.util.Vector;
public class Main {
static Vector city=new Vector<String>();
static Vector <Vector<String>> dig= new Vector <Vector<String>>();
static int Myfind(String s)
{
for(int i=0;i<city.size();i++)
{
if(city.get(i).equals(s)) {
return i;
}
}
return -1;
}
public static void main(String[] args) {
int n;
Scanner in=new Scanner(System.in);
n=in.nextInt();
for(int i=0;i<n;i++)
{
String d,c;
d=in.next();
c=in.next();
int flag=Myfind(c);
if(flag==-1){
city.addElement(c);
dig.addElement(new Vector<String>());
dig.get(city.size()-1).addElement(d);
}
else dig.get(flag).addElement(d);
}
for(int i=0;i<city.size();i++)
{
System.out.println(city.get(i)+" "+dig.get(i).size());
for(int j = 0; j< dig.get(i).size(); j++)
System.out.println(dig.get(i).get(j));
}
}
}
Queue队列
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
static Queue<String> V=new LinkedList<String>();
static Queue<String> N=new LinkedList<String>();
public static void main(String[] args) {
int M;
Scanner in=new Scanner(System.in);
M=in.nextInt();
while(M>0) //
{
M--;
String op,name,type;
op=in.next();
// System.out.println("op"+op);
if(op.contains("IN"))
{
name=in.next();
type=in.next();
if(type.contains("V")) {
V.offer(name);
}
else {
N.offer(name);
}
// System.out.println("name:"+name+"type:"+type);
// System.out.println(Vqueue);
}
else
{
type=in.next();
if(type.contains("V")){
V.poll();
}
else {
N.poll();
}
// System.out.println("type"+type);
}
}
while(V.size()!=0)
{
System.out.println(V.poll());
}
while(N.size()!=0)
{
System.out.println(N.poll());
}
}
}
Map映射
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
public class Main {
static Map mp=new TreeMap();
public static void main(String[] args)
{
int n;
boolean flag=false;
Scanner in=new Scanner(System.in);
String ans="NO";
n=in.nextInt();
for(int i=0;i<n;i++)
{
String word;
word=in.next();
// System.out.println(Hx(word));
if(flag) continue;
if(mp.containsKey(word)){
flag=true;
ans=word;
}
else {
mp.put(word,true);
}
}
System.out.println(ans);
}
}
递归算法:
do(a,b,c...)
{
//递归终止条件,即出口
if(a==? ,b==? ,....) return
//递归条件
if(条件1)
do(参数1)
else(条件2)
do(参数2)
}
如本题,各子式间存在计算关系,可以化为:
do(a)
{
if(a==0) return 0;
if(a==1) return 1;
return do(a-1)+do(a-2);
}
组合型枚举就是让你在 n 个中,随机选出 m 个,问你有多少种方案,而且每一种方案选择了哪 m 个,这就是组合型枚举
public class Main {
static int n;
static int m;//选m个数
static Vector<Integer> chosen = new Vector<Integer>();
static <object> void calc(int x) {
if (chosen.size() > m || chosen.size() + (n - x + 1) < m) //剪枝
return;
if (x == n + 1) { //选够了m个数输出
String ansTem = "";
for (int i = 0; i < chosen.size(); i++)
System.out.print(chosen.get(i)+" ");
System.out.println("");
return;
}
calc(x + 1);
chosen.addElement(x);
calc(x + 1);
chosen.remove((Object)x);
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
m = in.nextInt();
calc(1);
}
}
排列型枚举相对组合型枚举就简单了一点,就是 n 个的全排列,即从 n 个中选取 n 个但是关心内部的顺序。
相比较组合只关心有多少个集合,而排列是关心集合内的排列方式。即排列型枚举就是寻找 AnnA_{n}^nAnn 问题。
static int n;
static int[] order =new int[20];
static boolean[] chosen =new boolean[20];
static <object> void calc(int x) {
if (x == n + 1) { //选够了m个数输出
String ansTem = "";
for (int i = 1; i <=n ; i++)
System.out.println(order[i]);
return;
}
for (int i = 1; i <= n; i++) {
if (chosen[i]) continue;
order[x] = i;
chosen[i] =true;
calc(x + 1);
chosen[i] = false;
order[x] = 0;
}
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
for (int i = 0; i < n; i++) {
String s;
s=in.next();
name.addElement(s);
}
calc(1);
}
差分算法解题的基本思路:
1、 b[1]=a[1];
2、 从第 2 项到 n 项,利用 b[i]=a[i]−a[i−1]b[i]=a[i]-a[i-1]b[i]=a[i]−a[i−1] 差分式;
3、 对于区间端点操作加减;
4、 差分还原(前缀和)。
注意是从1开始,从0开始还有讨论i=0 的情况,使用1的话 b[1]=a[1]-a[0]=a[1]-0;
首先假设有一个数组:
a[]={1 2 3 4 5 7 2}
差分后:
b[]={1 1 1 1 1 2 -5}
一般应用场景:
让你对区间 [l,r] 加减操作 N 次
如:
从第二个元素到第五个元素每个+3
从第二个元素到第四个元素每个-2
从第一个元素到第三个元素每个+1
....
这里我们先演示前三个:
对于每个 [l,r] 区间的加减操作都转化为对端点 l,r+1 的操作
从第二个元素到第五个元素每个+3:
转化为:[l]+3 并且 [r+1]-3
那么原序列变成了:
1 1 1 1 1 2 -5
1 4 1 1 1 -1 -5
然后我们按照 b[i]=b[i]+b[i-1] 复原:
1 5 6 7 8 7 2
去掉最后一项,跟原序列对比:
1 2 3 4 5 7 2
1 5 6 7 8 7 2
确实是都加上了 3。
我们继续操作:
从第二个元素到第四个元素每个-2
转化为:[l]-2 并且 [r+1]+2
那么序列变成了:
1 4 1 1 1 -1 -5
1 2 1 1 3 -1 -5
然后我们按照b[i]=b[i]+b[i-1] 复原
1 3 4 5 8 7 2
与上次复原后对比:
1 5 6 7 8 7 2
1 3 4 5 8 7 2
确实是按照操作执行了。
注意 Warning:
不用每次都复原,只用最后一次复原即可,这里我是演示给大家看。
我们最后直接做三次,最后还原:
从第二个元素到第五个元素每个+3
从第二个元素到第四个元素每个-2
从第一个元素到第三个元素每个+1
a[]={1 2 3 4 5 7 2}
原序列差分后:
b[]={1 1 1 1 1 2 -5}
2 号元素 + 3
6 号元素 - 3
2 号元素 - 2
5 号元素 + 2
1 号元素 + 1
4 号元素 - 1
差分序列变成:
2 2 1 0 3 -1 -5
复原后:
2 4 5 5 8 7 5
与原序列对比:
1 2 3 4 5 7 2
2 4 5 5 8 7 5
所以还是非常方便快捷的。
首先假设有一个数组:
1 2 3 4 5 7 2
前缀和后:
0 1 3 6 10 15 22 24
一般应用场景:
让你对区间 [l,r] 求和操作N次
如:
从第二个元素到第五个元素的和
从第二个元素到第四个元素的和
从第一个元素到第三个元素的和
....
这里我们先演示前三个:
对于每个 [l,r] 区间的求和操作转化为区间端点的加减操作
sum[l,r] =[r]-[l-1]
从第二个元素到第五个元素的和:
转化为:[5]-[1]
那么Sum[2,5]=[5]-[1]=14
且 2+3+4+5=14
确实是相等的,就是这么神奇。
我们继续操作:
从第二个元素到第四个元素的和
转化为:[4]-[1]
那么Sum[2,4]=[4]-[1]=9
且 2+3+4=9
我们继续操作:
从第一个元素到第三个元素的和
转化为:[3]-[0]
那么Sum[1,3]=[3]-[0]=6
且 1+2+3=6
符合题意,验证结束,咱么做个题目看一看
二分查找:
// 在单调递增序列a中查找>=x的数中最小的一个(即x或x的后继)
while (low < high) {
int mid = (low + high) / 2;
if (a[mid] >= x)
high= mid;
else
low = mid + 1;
}
// 在单调递增序列a中查找<=x的数中最大的一个(即x或x的前驱)
while (low < high) {
int mid = (low + high + 1) / 2;
if (a[mid] <= x)
low = mid;
else
high = mid - 1;
}
实数二分:
//令eps 为小于题目精度一个数即可。
//比如题目说保留4位小数,0.0001 这种的。那么eps 就可以设置为五位小数的任意一个数 0.00001- 0.00009 等等都可以。一般为了保证精度我们选取精度 /100 的那个小数,即设置 eps= 0.0001/100 =1e-6。
while (l + eps < r) {
double mid = (l + r) / 2;
if (pd(mid))
r = mid;
else
l = mid;
}
// 实数域二分,规定循环次数法
//通过循环一定次数达到精度要求,这个一般log2N< 精度即可。N为循环次数,在不超过时间复杂度的情况下,可以选择给N乘一个系数使得精度更高。
for (int i = 0; i < 100; i++) {
double mid = (l + r) / 2;
if (pd(mid))
r = mid;
else
l = mid;
}