KMP算法

  1. public class kmp {
  2. // KMP 算法
  3. // ss: 原串(string) pp: 匹配串(pattern)
  4. // " a b c a b c c a b b b c c a b y y
  5. // 0 0 0 0 1 2 3 0 1 2 0 0 0 0 1 2 0 0
  6. // 不回退原串 回退子串
  7. // 构建next数组保存 子串前缀特征 决定失败时回退的位置
  8. public static int strStr(String ss, String pp) {
  9. if (pp.isEmpty()) return 0;
  10. // 分别读取原串和匹配串的长度
  11. int n = ss.length(), m = pp.length();
  12. // 原串和匹配串前面都加空格,使其下标从 1 开始
  13. ss = " " + ss;
  14. pp = " " + pp;
  15. char[] s = ss.toCharArray();
  16. char[] p = pp.toCharArray();
  17. // 构建 next 数组,数组长度为匹配串的长度(next 数组是和匹配串相关的)
  18. int[] next = new int[m + 1];
  19. // 构造过程 i = 2,j = 0 开始,i 小于等于匹配串长度 【构造 i 从 2 开始】
  20. for (int i = 2, j = 0; i <= m; i++) {
  21. // 匹配不成功的话,j = next(j)
  22. while (j > 0 && p[i] != p[j + 1]) j = next[j];
  23. // 匹配成功的话,先让 j++
  24. if (p[i] == p[j + 1]) j++;
  25. // 更新 next[i],结束本次循环,i++
  26. next[i] = j;
  27. }
  28. // 匹配过程,i = 1,j = 0 开始,i 小于等于原串长度 【匹配 i 从 1 开始】
  29. for (int i = 1, j = 0; i <= n; i++) {
  30. // 匹配不成功 j = next(j)
  31. while (j > 0 && s[i] != p[j + 1]) j = next[j];
  32. // 匹配成功的话,先让 j++,结束本次循环后 i++
  33. if (s[i] == p[j + 1]) j++;
  34. // 整一段匹配成功,直接返回下标
  35. if (j == m) return i - m;
  36. }
  37. return -1;
  38. }
  39. }

矩阵快速幂

字典序

字典序排序

输入:n = 13
输出:[1,10,11,12,13,2,3,4,5,6,7,8,9]
class Solution {
    //递归 选择一个基数 然后往上加
    public List<Integer> lexicalOrder(int n) {
        List<Integer> ans = new ArrayList();
        dfs(0, 1, n, ans);
        return ans;

    }

    public void dfs(int base, int start, int n, List<Integer> ans) {
        if (base > n) return;
        for(int i = start; i < 10; i++) {
            int num = i + base;
            if(num <= n) {
                ans.add(num);
                dfs(num*10, 0, n , ans);
            }
        }
    }
}

字典序的第K小数字

给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。
输入:  n: 13   k: 2
输出:  10
解释:
字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9],所以第二小的数字是 10。

其他 - 图1

class Solution {
    public int findKthNumber(int n, int k) {
        long cur = 1; // 当前遍历到的数字,从1(根)出发
        k = k - 1; // 从1出发开始往后按字典序从小到大的顺序走k-1步到达的就是 字典序的第K小数字

        while(k > 0){
            int nodes = getNodes(n, cur);
            if(k >= nodes){ // 向右侧节点走:字典序上升nodes位
                k =  k - nodes;
                cur++;  // 当前数字 cur = cur + 1
            }else{ // 向下往最左孩子节点走:字典序上升1位
                k = k - 1; 
                cur *= 10;  // 当前数字 cur = cur * 10
            }
        }
        return (int)cur; // 最后cur停在的数字就是字典序的第K小数字
    }

    // 计算以cur为根的子树节点数目,所有节点的值必须 <= n
    private int getNodes(int n, long cur){
        long next = cur + 1; // 当前节点右侧右边节点的值
        long totalNodes = 0; // 记录子树中的全部节点数目
        while(cur <= n){
            totalNodes += Math.min(n - cur + 1, next - cur);
            next *= 10;
            cur *= 10;
        }
        return (int)totalNodes;
    }
}

最大异或值

给你一个整数数组 nums ,返回 nums[i] XOR nums[j] 的最大运算结果,其中 0 ≤ i ≤ j < n 

输入:nums = [3,10,5,25,2,8]
输出:28
解释:最大运算结果是 5 XOR 25 = 28.
//使用哈希表实现
public class Solution {
    // 先确定高位,再确定低位(有点贪心算法的意思),才能保证这道题的最大性质
    // 一位接着一位去确定这个数位的大小
    // 利用性质: a ^ b = c ,则 a ^ c = b,且 b ^ c = a
    public int findMaximumXOR(int[] nums) {
        int res = 0;
        int mask = 0;
        for (int i = 30; i >= 0; i--) {
            // 注意点1:注意保留前缀的方法,mask 是这样得来的
            // 用异或也是可以的 mask = mask ^ (1 << i);
            mask = mask | (1 << i);

            // System.out.println(Integer.toBinaryString(mask));
            Set<Integer> set = new HashSet<>();
            for (int num : nums) {
                // 注意点2:这里使用 & ,保留前缀的意思(从高位到低位)
                set.add(num & mask);
            }

            // 这里先假定第 n 位为 1 ,前 n-1 位 res 为之前迭代求得
            int temp = res | (1 << i);
            for (Integer prefix : set) {
                if (set.contains(prefix ^ temp)) {
                    res = temp;
                    break;
                }
            }
        }
        return res;
    }
}

//使用Trie树
class Solution {
    // static 成员整个类独一份,只有在类首次加载时才会创建,因此只会被 new 一次
    static int N = (int)1e6;
    static int[][] trie = new int[N][2];
    static int idx = 0;
    // 每跑一个数据,会被实例化一次,每次实例化的时候被调用,做清理工作
    public Solution() {
        for (int i = 0; i <= idx; i++) {
            Arrays.fill(trie[i], 0);
        }
        idx = 0;
    }
    void add(int x) {
        int p = 0;
        for (int i = 31; i >= 0; i--) {
            int u = (x >> i) & 1;
            if (trie[p][u] == 0) trie[p][u] = ++idx;
            p = trie[p][u];
        }
    }
    int getVal(int x) {
        int ans = 0;
        int p = 0;
        for (int i = 31; i >= 0; i--) {
            int a = (x >> i) & 1, b = 1 - a;
            if (trie[p][b] != 0) {
                ans |= (b << i);
                p = trie[p][b];
            } else {
                ans |= (a << i);
                p = trie[p][a];
            }
        }
        return ans;
    }
    public int findMaximumXOR(int[] nums) {
        int ans = 0;
        for (int i : nums) {
            add(i);
            int j = getVal(i);
            ans = Math.max(ans, i ^ j);
        }
        return ans;
    }
}

队列模拟栈

class MyStack {
    Queue<Integer> q1;
    Queue<Integer> q2;

    public MyStack() {
        q1 = new LinkedList();
        q2 = new LinkedList();
    }

    public void push(int x) {
        q2.add(x);
        while(!q1.isEmpty()) {
            q2.add(q1.poll());
        }
        Queue<Integer> temp = q1;
        q1 = q2;
        q2 = temp;
    }

    public int pop() {
        return q1.poll();
    }

    public int top() {
        return q1.peek();
    }

    public boolean empty() {
        return q1.isEmpty();
    }
}

设计哈希映射

//链地址法
//拉链法
class MyHashMap {
    private static final int BASE = 769;
    private LinkedList[] table;

    private class Entry {
        private int key;
        private int value;

        public Entry(int key, int value) {
            this.key = key;
            this.value = value;
        }

        public int getKey() {
            return key;
        }

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }
    }

    public MyHashMap() {
        table = new LinkedList[BASE];
        for(int i = 0; i < BASE; i++) {
            table[i] = new LinkedList();
        }
    }

    public void put(int key, int value) {
        int hashCode = hash(key);
        Iterator<Entry> iterator = table[hashCode].iterator();
        while(iterator.hasNext()) {
            Entry entry = iterator.next();
            if(entry.getKey() == key) {
                entry.setValue(value);
                return;
            }
        }
        table[hashCode].addLast(new Entry(key, value));
    }

    public int get(int key) {
        int hashCode = hash(key);
        Iterator<Entry> iterator = table[hashCode].iterator();
        while(iterator.hasNext()) {
            Entry entry = iterator.next();
            if(entry.getKey() == key) {
                return entry.value;
            }
        }
        return -1;
    }

    public void remove(int key) {
        int hashCode = hash(key);

        Iterator<Entry> iterator = table[hashCode].iterator();
        while(iterator.hasNext()) {
            Entry entry = iterator.next();
            if(entry.key == key) {
                table[hashCode].remove(entry);
                return;
            }
        }
    }
    private static int hash(int key) {
        return key % BASE;
    }
}

前缀和

模版

class Solution {
    public void func(int[] nums) {
        int n = nums.length;
        int[] sum = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            sum[i] = sum[i - 1] + nums[i - 1];
        }
    }
}