您的位置:首页 > 其它

算法竞赛入门读书笔记(自用,慎入)

2016-05-09 11:29 375 查看

例3.2最长回文子串



书中讲的很好,主要难点在三处

1. 输入字符串要含有空格,对应java下的readLine()方法即可

2. 查找回文串,暴力搜索,书中从中间搜索,没感觉复杂度降低多少

3. 原样输出,这就需要记录去除特殊符号后的串对应原串相应位置.(很常用的方法)

import java.util.Scanner;

public class Test {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int max = 0,x = 0,y = 0;//分别记录最大值,和对应原位置的下标
String str = input.nextLine();
int[] p = new int[str.length()];//记录原位置的数组
char[] s = new char[str.length()];//记录去除特舒符号后的串
//去除特殊符号并记录新数组中元素在原数组中位置
for (int i = 0,m = 0; i < str.length(); i++) {
if (Character.isLetter(str.charAt(i))) {
p[m] = i;
s[m++] = Character.toLowerCase(str.charAt(i));
}
}
//开始查找回文串,利用StringBuilder的reverse来进行比较即可
//基本思路就是暴力方法
String strTemp = new String(s).trim();
for (int i = 0; i < strTemp.length(); i++) {
for (int j = i+1; j < strTemp.length(); j++) {
StringBuilder builder = new StringBuilder(strTemp.substring(i, j));
//当两者正反一致的时候说明为回文串
if (builder.toString().equals(builder.reverse().toString())) {
if (j-i > max) {
max = j - i;
x = i;
y = j;
}
}
}
}
System.out.println(str.substring(p[x],p[y]));
}
}


5.1.3周期串



对于周期性问题,大多数都可以通过取余来得到一定的周期关系.对于定长字符串最好的操作还是转换成字符数组,方便修改和查找.

import java.util.Arrays;

public class Test2 {
public static void main(String[] args) {
String str = "aaa";
char[] c = (str).toCharArray();
//i的值实际上就是循环节的大小,故要从1开始,还可以避免除0
for (int i = 1; i < c.length; i++) {
boolean iscan = true;//标志变量
if ((c.length) % i == 0) {//如果能整除i,则表示可能为当前这个子串
for (int j = i; j < c.length; j++) {
//因为是循环,这里利用取余来判断
if (c[j] != c[j%i]) {
iscan = false;
break;
}
}
if (iscan) {
System.out.println(i);
}
}
}
System.out.println(Arrays.toString(c));
}
}


5.31 6174问题



传统的学习循环,学习怎么取出数字的指定位数

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Scanner;

public class Test3 {
public static void main(String[] args) {
//利用hash链表来存储每次计算产生的结果
LinkedHashMap<Integer, Integer> map = new LinkedHashMap<>();
Scanner input = new Scanner(System.in);
int n = input.nextInt();
map.put(n, n);
int count = 0;
//循环小于1000,也就是最多找1000个整数
while(count <= 1000){
int max = getNum(n, true);
int min = getNum(n, false);
n = max - min;
//如果计算过了则退出
if (map.containsKey(n)) {
break;
}
map.put(n, n);
count++;
}
System.out.println(map.toString()+"---"+n);
}
/**
* 输入一个整数,计算出他正排和倒排的值
* @param n
* @param order true表示正排
* @return
*/
private static int getNum(int n,boolean order){
int[] arr = new int[4];
int i = 0;
while(n>0){
arr[i] = n % 10;
n = n / 10;
i++;
}
Arrays.sort(arr);
if (order) {
return arr[3]*1000+arr[2]*100+arr[1]*10+arr[0];
}
return arr[0]*1000+arr[1]*100+arr[2]*10+arr[3];
}
}


5.31 字母重排

这里涉及了字符串的比较,一位一位的比较太过于繁琐,所以可以先排序后比较,就方便很多了

5.41 Cantor数表

这种找规律得题一般可以用技巧,先用预处理把一些可能用到计算的数据先保存起来,后面直接用,另外注意java里面写好的二分查找方法,很实用,还能自定义比较器

import java.util.Arrays;
import java.util.Scanner;

public class Test4 {
public static void main(String[] args) {
//预处理计算出前K项的和
int arr[] = new int[1000];
for (int i = 1; i < arr.length; i++) {
arr[i] = (i+1)*i/2;
}
System.out.println(Arrays.toString(arr));
//主程序开始
Scanner input = new Scanner(System.in);
//      int n = input.nextInt();
int n = 7;
//二分查找,找到比这个数小的位置的k
int mid = Arrays.binarySearch(arr, n);
if (mid<0) {//如果没找到则返回插入位置,也就是第一个小于n得位置
mid = -mid-1;//确定该元素是第mid+1斜线上的元素
System.out.println((mid+1+n-arr[mid])+"/"+(arr[mid]-n+1));
}else {//如果找到了则直接输出
System.out.println(mid+"/"+(n-arr[mid]+1));
}

}
}


6.1.1卡片游戏



主要是java队列得简单用法,代码很清晰,另外这是双端队列,可以直接操作队头或者队尾

import java.util.ArrayDeque;

public class Test5 {

public static void main(String[] args) {
//构造一个初始容量为10得队列
ArrayDeque<Integer> queue = new ArrayDeque<>(10);
//对于队列一般实用offer,poll,peek等方法,这几个可以通过返回值判断是否成功
for (int i = 1; i < 8; i++) {
queue.offer(i);
}
while(!queue.isEmpty()){
System.out.println(queue.pollFirst());;
if (queue.peek() != null) {
queue.offer(queue.poll());
}
}
}
}


6.3.1小球下落

对于二叉树得数组表示法,因为知道了深度就知道二叉树总节点数,因为二叉树本身是等比数列,可以用
1<<D
来表示其节点数,而且如果按从上到下从左到右排序得话,节点k得左孩子是2k,右孩子是2k+1



import java.util.Arrays;
import java.util.Scanner;

public class Test6 {

public static void main(String[] args) {
int D,I;
Scanner input = new Scanner(System.in);
D = input.nextInt();
I = input.nextInt();
boolean[] s = new boolean[1<<D];//s[0]不用
for (int j = 0; j < I; j++) {//对小球循环
//每一个小球滚落模拟
int j2 = 1;
for (; ;) {
s[j2] = !s[j2];//转动开关
if (s[j2]) {//关闭向左
j2 = 2*j2;
}else {//开启向右
j2 = 2*j2+1;

}
if (j2 > s.length-1) {
break;
}
}
System.out.println(j2/2);//除以2找到最后经过的节点

}
System.out.println(Arrays.toString(s));
}
}


6.4最大公约数问题

最大公约数最方便的就是辗转相除法,最小公倍数就是a*b/gcd(a,b)

public static int gcd(int a, int b) {
//基本公式如果a%b!=0  那么 gcd(a,b) = gcd(b,a%b)
while (true) {
if ((a = a % b) == 0)
return b;
if ((b = b % a) == 0)
return a;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: