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

例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));
    }
}
时间: 2024-08-01 14:24:45

算法竞赛入门读书笔记(自用,慎入)的相关文章

《算法导论》读书笔记之第16章 0-1背包问题—动态规划求解

原文:http://www.cnblogs.com/Anker/archive/2013/05/04/3059070.html 1.前言 前段时间忙着搞毕业论文,看书效率不高,导致博客一个多月没有更新了.前段时间真是有些堕落啊,混日子的感觉,很少不爽.今天开始继续看算法导论.今天继续学习动态规划和贪心算法.首先简单的介绍一下动态规划与贪心算法的各自特点及其区别.然后针对0-1背包问题进行讨论.最后给出一个简单的测试例子,联系动态规划实现0-1背包问题. 2.动态规划与贪心算法 关于动态规划的总结

拓扑排序(算法竞赛入门经典)

拓扑排序的定义: 把每个变量看成一个点,”小于“或者”先后“关系看成有向边,则我们得到一个有向图.这样我们的任务实际上是把一个图的所有节点排序,使每一条有向边的(u,v)对应的u都排在v之前,在图论中,我们称之为拓扑排序.不难发现,如果一个有向图里存在回路,则不存在拓扑排序(如果设置一个标志数组,我们可以发现回路中的点一直处于正在被访问状态,这可以作为拓扑排序的结束条件). 我们先看一个样例: 下面我们用邻接矩阵存储这张图:   0 1 2 3 0 0 1 1 1 1 0 0 1 1 2 0 0

《算法导论》读书笔记(一)

本章是本书的开篇,介绍了什么是算法,为什么要学习算法,算法在计算机中的地位及作用. 算法(algorithm)简单来说就是定义良好的计算机过程,它取一个或一组值作为输入,并产生出一个或一组值作为输出.即算法就是一系列的计算步骤,用来将输入数据转换成输出数据. 书中有一句话非常好: Having a solid base of algorithm knowledge and technique is one characteristic that separates the truly skill

《算法竞赛入门经典第二版》 P35 习题2-4 子序列的和(subsequence)

/* <算法竞赛入门经典第二版> P35 习题2-4: 输入两个正整数 n < m < 10^6,输出 (1/n)^2 + 1/(n+1)^2 +……+ 1/m^2,保留5位小数. 输入包含多组数据,结束标志为 m=n=0. 有错欢迎指出^_^ */ #include<stdio.h> int main() { int m,n,i,j=1; while(scanf("%d%d",&m,&n) != EOF) { double sum

算法竞赛入门经典_4.3_递归

看代码 #include <stdio.h> int f(int n){ return n == 0?1:f(n-1)*n; } int main() { printf("%d\n", f(5)); return 0; } 上面f函数使用了递归,递归由两部分组成,一是递归头,二是递归体. 我们使用gcc调试工具 H:\编程书籍学习\算法竞赛入门经典2代码\算法入门经典第四章>b f 'b' 不是内部或外部命令,也不是可运行的程序 或批处理文件. H:\编程书籍学习\算

《算法竞赛入门经典(第二版)》pdf

下载地址:网盘下载 内容简介  · · · · · · <算法竞赛入门经典(第2版)>是一本算法竞赛的入门与提高教材,把C/C++语言.算法和解题有机地结合在一起,淡化理论,注重学习方法和实践技巧.全书内容分为12 章,包括程序设计入门.循环结构程序设计.数组和字符串.函数和递归.C++与STL入门.数据结构基础.暴力求解法.高效算法设计.动态规划初步.数学概念与方法.图论模型与算法.高级专题等内容,覆盖了算法竞赛入门和提高所需的主要知识点,并含有大量例题和习题.书中的代码规范.简洁.易懂,不

《算法竞赛入门经典》动态规划复习

codevs 4979 数塔 1 #define N 100 2 #include<iostream> 3 using namespace std; 4 #include<cstdio> 5 int a[N][N],b[N][N],n; 6 int main() 7 { 8 scanf("%d",&n); 9 for(int i=1;i<=n;++i) 10 for(int j=1;j<=i;++j) 11 { 12 scanf("

算法竞赛入门经典训练指南

最近在看算法竞赛入门经典训练指南这本书,书中不错的算法我将在博客中发布,和大家共同学习. 题目: 在你的王国里有一条n个头的恶龙,你希望雇一些骑士把它杀死(即砍掉所有头).村里有m个骑士可以雇佣,一个能力值为m的骑士可以砍掉一个直径不超过x的头,且需要支付x个金币.如何雇佣骑士才能砍掉恶龙的所有头,且需要支付的金币最少?注意,一个骑士只能砍一个头(且不能被雇佣两次). 输入格式: 输入包含多组数据.每组数据的第一行为正整数m和n(1<=m,n<=20 000):以下m行每行为一个整数,即恶龙每

《ACM/ICPC 算法训练教程》读书笔记 之 数据结构(线段树详解)

依然延续第一篇读书笔记,这一篇是基于<ACM/ICPC 算法训练教程>上关于线段树的讲解的总结和修改(这本书在线段树这里Error非常多),但是总体来说这本书关于具体算法的讲解和案例都是不错的. 线段树简介 这是一种二叉搜索树,类似于区间树,是一种描述线段的树形数据结构,也是ACMer必学的一种数据结构,主要用于查询对一段数据的处理和存储查询,对时间度的优化也是较为明显的,优化后的时间复杂为O(logN).此外,线段树还可以拓展为点树,ZWK线段树等等,与此类似的还有树状数组等等. 例如:要将