LeetCode算法总结

防止重复路径

847
通过状态压缩,记录每次 入节点 的路径
boolean[][] seen = new boolean[n][1 << n];

最短路问题

542

图构建优化

127
通过增加虚拟节点

字典树(前缀树)

class Trie {
    boolean q;
    String val;
    Set<Trie> nexts;

    public Trie() {
        this.nexts=new HashSet();
    }

    public void insert(String word) {
        Trie trie=this;
        boolean has;
        while(word.length()>0){
            has=false;
            for(Trie t:trie.nexts){
                if(t.val.equals(word.substring(0,1))){
                    word=word.substring(1);
                    trie=t;
                    has=true;
                    break;
                }
            }
            if(!has){
                break;
            }
        }
        if(word.length()==0){
            trie.q=true;
        }
        Trie t;
        while(word.length()>0){
            t=new Trie();
            t.q=false;
            t.val=word.substring(0,1);
            word=word.substring(1);
            trie.nexts.add(t);
            trie=t;
        }
        trie.q=true;
    }

    public void print(){
        for(Trie t:this.nexts){
            System.out.println(t.val+" "+t.q);
            print(t);
        }
    }

    public void print(Trie t){
        for(Trie trie:t.nexts){
            System.out.println(trie.val+" "+trie.q);
            print(trie);
        }
    }

    public boolean search(String word) {
        Trie trie=this;
        boolean has;
        while(word.length()>0){
            has=false;
            for(Trie t:trie.nexts){
                if(t.val.equals(word.substring(0,1))){
                    word=word.substring(1);
                    trie=t;
                    has=true;
                    break;
                }
            }
            if(!has){
                return false;
            }
        }
        if(!trie.q){
            return false;
        }

        return true;
    }

    public boolean startsWith(String prefix) {
        Trie trie=this;
        boolean has;
        while(prefix.length()>0){
            has=false;
            for(Trie t:trie.nexts){
                if(t.val.equals(prefix.substring(0,1))){
                    prefix=prefix.substring(1);
                    trie=t;
                    has=true;
                    break;
                }
            }
            if(!has){
                return false;
            }
        }

        return true;
    }
}

单调栈

	/**
     * 单调栈
     * 数组中没有重复值
     *
     * @param arr
     * @return
     */
    public static int[][] getNearLessNoRepeat(int[] arr) {
        int[][] ret = new int[arr.length][2];
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < arr.length; i++) {
            while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
                //弹栈并记录相关信息
                int index = stack.pop();
                ret[index][1] = i;//记录右边离index最近且小的元素
                ret[index][0] = stack.isEmpty() ? -1 : stack.peek();//记录左边离index最近且小的元素
            }
            stack.push(i);
        }
        while (!stack.isEmpty()) {
            int index = stack.pop();
            ret[index][1] = -1;//没有右边最近且小的元素
            ret[index][0] = stack.isEmpty() ? -1 : stack.peek();
        }
        return ret;
    }

    /**
     * 单调栈
     * 数组中有重复值
     *
     * @param arr
     * @return
     */
    public static int[][] getNearLess(int[] arr) {
        int[][] res = new int[arr.length][2];
        Stack<List<Integer>> stack = new Stack<>();
        for (int i = 0; i < arr.length; i++) {
            while (!stack.isEmpty() && arr[stack.peek().get(0)] > arr[i]) {
                List<Integer> list = stack.pop();
                //左边最近且小的元素为栈顶集合最后一个索引
                Integer left = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
                for (Integer integer : list) {
                    res[integer][0] = left;
                    res[integer][1] = i;
                }
            }
            //判断当前栈顶值是否等于待入栈元素的值
            if (!stack.isEmpty() && arr[stack.peek().get(0)] == arr[i]) {
                stack.peek().add(i);
            } else {
                ArrayList<Integer> list = new ArrayList<>();
                list.add(i);
                stack.push(list);
            }
        }
        while (!stack.isEmpty()) {
            List<Integer> pop = stack.pop();
            Integer left = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
            for (Integer integer : pop) {
                res[integer][0] = left;
                res[integer][1] = -1;
            }
        }
        return res;
    }

前缀和

存在数组nums,长度为n
前缀和就是将数组前 nums[i]=前 i 项和。
如果求连续数组长度的话,配合哈希表最佳。哈希表可存储最先出现nums[i]值的下标。
相关题:力扣525题

并查集

并查集是一种树型的数据结构。它的特点是由子结点找到父亲结点,用于处理一些不交集的合并及查询问题。
Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
Union:将两个子集合并成同一个集合。

class UnionFind {
    int[] parents;

    public UnionFind(int totalNodes) {
        parents = new int[totalNodes];
        for (int i = 0; i < totalNodes; i++) {
            parents[i] = i;
        }
    }

    /**
     * 合并连通区域是通过find来操作的, 即看这两个节点是不是在一个连通区域内
     * @param node1
     * @param node2
     */
    void union(int node1, int node2) {
        int root1 = find(node1);
        int root2 = find(node2);
        if (root1 != root2) {
            parents[root2] = root1;
        }
    }

    int find(int node) {
        while (parents[node] != node) {
            // 当前节点的父节点 指向父节点的父节点.
            // 保证一个连通区域最终的parents只有一个.
            parents[node] = parents[parents[node]];
            node = parents[node];
        }

        return node;
    }

    boolean isConnected(int node1, int node2) {
        return find(node1) == find(node2);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值