大數據算法系列10:字符串檢驗算法 一. 字符串檢驗算法 二. 練習 參考:

一. 字符串檢驗算法

字符串檢驗算法:

奇偶校驗:
磁盤陣列的Raid5就是使用了奇偶校驗。

海明碼:

二. 練習

2.1 面試題(輸出字符串的排列組合)

題目:

分析:
採用遞歸加動態規劃的思路,加上恢復現場的原理,同時解決。

代碼:

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

class Main {
  public static Set<String> getPermutation(String str) {

    //創建 set 集合以避免重複排列
    Set<String> permutations = new HashSet<String>();

    //檢查字符串是否爲空
    if (str == null) {
      return null;
    } else if (str.length() == 0) {
      //遞歸的終止條件
      permutations.add("");
      return permutations;
    }

    //得到第一個字符
    char first = str.charAt(0);

    //獲取剩餘的子字符串
    String sub = str.substring(1);

    //遞歸調用getPersertion()
    Set<String> words = getPermutation(sub);

    //遍歷 words
    for (String strNew : words) {
      for (int i = 0;i<=strNew.length();i++){

        //將排列插入到set集合中
        permutations.add(strNew.substring(0, i) + first + strNew.substring(i));
      }
    }
    return permutations;
  }

  public static void main(String[] args) {

    //創建scanner類的對象
    Scanner input = new Scanner(System.in);

    // 接受用戶的輸入
    System.out.print("輸入字符串: ");
    String data = input.nextLine();
    System.out.println(data + "  的排列組合有: \n" + getPermutation(data));
    }
}

2.2 POJ2262(求奇質素之和)

題目:

代碼:

import java.util.Scanner;


public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        
        while(true) {
            int t=sc.nextInt();
            if(t==0)break;//t等於0退出
            for (int i = 3; i <=t/2; i+=2) {//從3開始,因爲必須是奇素數,就不考慮2了
                if(isPrime(i)&&isPrime(t-i)) {
                    System.out.println(t+" = "+i+" + "+(t-i));
                    break;
                }
            }
            
        }
    }
    private static boolean isPrime(int i) {
        if(i==2||i==3) {//等於2,3直接返回是素數
            return true;
        }
        //3之後的素數,一定,在6的兩邊
        if(i%6!=1 && i%6!=5) {//不在6的左右兩邊,一定不是素數
            return false;
        }
        //在6的左右兩邊的數,也有可能不是素數
        int sqrt=(int)Math.sqrt(i);
        for (int j = 5; j <=sqrt ; j+=6) {
            if(i%j==0 || i%(j+2)==0) {
                return false;
            }
            
        }
        return true;
    }
}

2.3 開門遊戲

題目:

分析:
用0表示關門,用1表示開門,把數據放到一個數組裏面。
然後寫個if判斷,每次改變裝填,最後給數組求和,就能知道有多少開門的。

2.4 Uva106(費馬大定律)

題目:

分析:
拆解開了,根據公式進行循環判斷即可。

2.5 POJ3744(踩地雷)

大意:
輸入n,代表一位童子兵要穿過一條路,路上有些地方放着n個地雷(1<=n<=10)。再輸入p,代表這位童子兵非常好玩,走路一蹦一跳的。每次他在 i 位置有 p 的概率走一步到 i+1 ,或者 (1-p) 的概率跳一步到 i+2。輸入n個數,代表n個地雷的位置(1<=n<=100000000),童子兵初始在1位置,求他安全通過這條道路的概率。

分析:
如果k 號位有雷,那麼安全通過這個雷只可能是在 k-1 號位選擇走兩步到 k+1 號位。因此,可以得到如下結論:在第 i 個雷的被處理掉的概率就是從 a[i-1]+1 號位到 a[i] 號位的概率。於是,可以用 1 減去就可以求出安全通過第 i個雷的概率,最後乘起來即可,比較悲劇的是數據很大,所以需要用到矩陣快速冪……

類似斐波那契數列,有ans[i]=pans[i-1]+(1-p)ans[i-2]

2.6 POJ3233(矩陣計算)

題目:

分析:

2.7 POJ1226(哈希)

大意:
多組數據,每組n個字符串,尋找最長的X,使得對n個字符串中的任意一個,X或者X反轉過來的字符串是其子串。(輸出X的長度即可)

分析:
這道好像KMP或者後綴數組都能做,但我還是習慣用哈希。此題可以先二分這個長度(顯然如果某個長度滿足那麼小於這個長度的串也是能找到的),不妨記這個長度爲len。然後呢,以第一個字符串爲標準,正一遍反一遍掃過去得到該字符串中,以i爲下標開始的長度爲len的子串的哈希值(不妨記爲h1[i]),以及其翻轉過來串對應的哈希值(不妨記爲h2[i])。同時,後面幾個字符串中長度爲len的子串的哈希值也可處理出來,放到容器裏。接下來,就是看是否存在這樣的i,使得剩餘n-1個字符串對應的n-1個容器裏要麼含有h1[i],要麼含有h2[i]。如果是則len可以,所求長度肯定大於等於len;否則,所求長度小於len。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.StringTokenizer;
 
class Reader {
    static BufferedReader reader;
    static StringTokenizer tokenizer;
 
    static void init(InputStream input) {
        reader = new BufferedReader(new InputStreamReader(input));
        tokenizer = new StringTokenizer("");
    }
 
    static String next() throws IOException {
        while (!tokenizer.hasMoreTokens()) {
            tokenizer = new StringTokenizer(reader.readLine());
        }
        return tokenizer.nextToken();
    }
 
    static int nextInt() throws IOException {
        return Integer.parseInt(next());
    }
}
 
public class Main {
 
    /**
     * @param args
     */
    static int t, n, cnt, len1;
    static char ch[][];
    static int hash1[], hashin[];
    static HashSet<Integer> hashSet[];
    static String str;
    static long mul = 100000007;
    static long monum = Integer.MAX_VALUE;
    static long mulnum;
 
    private static boolean isOk(int num) {
        hashSet = new HashSet[n + 1];
        for (int i = 1; i <= n; i++)
            hashSet[i] = new HashSet<Integer>();
        mulnum = 1;
        for (int i = 1; i <= num; i++)
            mulnum = (mulnum * mul) % monum;
        long v;
        for (int i = 2; i <= n; i++) {
            if (ch[i].length < num)
                return false;
            v = 0;
            for (int j = 0; j < num; j++)
                v = (v * mul + (long) ch[i][j]) % monum;
            hashSet[i].add((int) v);
            for (int j = num; j < ch[i].length; j++) {
                v = (v * mul + (long) ch[i][j]) % monum;
                v = ((v - mulnum * (long) ch[i][j - num]) % monum + monum)
                        % monum;
                hashSet[i].add((int) v);
            }
        }
        hash1 = new int[len1 + 1];
        hashin = new int[len1 + 1];
        v = 0;
        for (int i = 0; i < num; i++) {
            v = (v * mul + (long) ch[1][i]) % monum;
        }
        hash1[1] = (int) v;
        for (int i = num; i < len1; i++) {
            v = (v * mul + (long) ch[1][i]) % monum;
            v = ((v - mulnum * (long) ch[1][i - num]) % monum + monum) % monum;
            hash1[i - num + 2] = (int) v;
        }
        v = 0;
        for (int i = len1 - 1; i >= len1 - num; i--) {
            v = (v * mul + (long) ch[1][i]) % monum;
        }
        hashin[len1 - num + 1] = (int) v;
        for (int i = len1 - num - 1; i >= 0; i--) {
            v = (v * mul + (long) ch[1][i]) % monum;
            v = ((v - mulnum * (long) ch[1][i + num]) % monum + monum) % monum;
            hashin[i + 1] = (int) v;
        }
        boolean flag;
        for (int i = 1; i <= len1; i++) {
            flag = true;
            for (int j = 2; j <= n; j++)
                if ((!hashSet[j].contains(hash1[i]))
                        && (!hashSet[j].contains(hashin[i]))) {
                    flag = false;
                    break;
                }
            if (flag)
                return true;
        }
        return false;
    }
 
    private static void deal() {
        len1 = ch[1].length;
        int l = 0;
        int r = ch[1].length;
        if (n == 1) {
            System.out.println(r);
            return;
        }
        int mid;
        while (r - l > 1) {
            mid = (l + r) / 2;
            if (isOk(mid))
                l = mid;
            else
                r = mid;
        }
        if (isOk(r))
            System.out.println(r);
        else
            System.out.println((r - 1));
    }
 
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        Reader.init(System.in);
        t = Reader.nextInt();
        ch = new char[101][];
        for (int casenum = 1; casenum <= t; casenum++) {
            n = Reader.nextInt();
            for (int i = 1; i <= n; i++) {
                str = Reader.next();
                ch[i] = str.toCharArray();
            }
            deal();
        }
    }
 
}

2.8 POJ2440(DNA)

大意:
L位由0和1組成的基因,基因中不能包含子串101以及111,求這樣的基因數(L<=10^8)

分析:
快速冪
https://blog.csdn.net/weixin_45987345/article/details/116033056

10^8,果斷快速冪。
先倒着推一下,然後再暴力打數據驗證想法,最後找循環節爲200就可以

a[n]表示長度爲n的情況數,第n位只有0或1兩種情況

當第n位爲0時,前一位爲0或1都可以,即a[n-1]

當第n位爲1,n-1位爲0時,則n-2位只能爲0,n-3位任意取,即a[n-3],

當第n位爲1,n-1位爲1時,則n-2位只能爲0,n-3位只能爲0,n-4位任意取,即a[n-4]
a[n]=a[n-1]+a[n-3]+a[n-4]

代碼:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
 
public class Main {
 
    /**
     * @param args
     */
    static int n, sum;
    static int mat1[][], nowmat[][];
    static BufferedReader reader;
    static String str;
 
    private static int[][] mulmat(int a[][], int b[][]) {
        int c[][] = new int[9][9];
        int val;
        for (int i = 1; i <= 8; i++)
            for (int j = 1; j <= 8; j++) {
                val = 0;
                for (int k = 1; k <= 8; k++)
                    val = (val + a[i][k] * b[k][j]) % 2005;
                c[i][j] = val;
            }
        return c;
    }
 
    private static int[][] mul(int n) {
        if (n == 1)
            return mat1;
        else {
            int mat[][] = mul(n / 2);
            mat = mulmat(mat, mat);
            if (n % 2 == 1)
                mat = mulmat(mat, mat1);
            return mat;
        }
    }
 
    private static void init() {
        mat1 = new int[9][9];
        mat1[1][1] = 1;
        mat1[1][5] = 1;
        mat1[2][1] = 1;
        mat1[2][5] = 1;
        mat1[3][2] = 1;
        mat1[4][2] = 1;
        mat1[5][3] = 1;
        mat1[5][7] = 1;
        mat1[7][4] = 1;
    }
 
    public static void main(String[] args) throws NumberFormatException,
            IOException {
        // TODO Auto-generated method stub
        reader = new BufferedReader(new InputStreamReader(System.in));
        while ((str = reader.readLine()) != null) {
            n = Integer.parseInt(str);
            if (n == 1)
                System.out.println(2);
            else if (n == 2)
                System.out.println(4);
            else if (n == 3)
                System.out.println(6);
            else {
                init();
                nowmat = mul(n - 3);
                sum = 0;
                for (int i = 1; i <= 8; i++)
                    for (int j = 1; j <= 8; j++)
                        sum = (sum + nowmat[i][j]) % 2005;
                System.out.println(sum);
            }
        }
    }
 
}

2.9 POJ3735(mat乘法優化)

大意:
對於n只貓,現在我們有g,e,s三種操作:

  1. g是讓第a只貓得到一個花生
  2. e是讓第a只貓的花生全部沒有
  3. s是讓第a只貓和第b只貓的花生互換

一共有K次操作,這還不算完

要我們重複m次這些操作後,得出的每隻貓的花生個數

分析:
m很大,考慮矩陣變化,考慮每一個變化過程,由於有加一,將初始矩陣末尾增加一,方便進行操作,然後有如下變換

參考:

  1. http://www.dataguru.cn/article-5747-1.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章