算法学习笔记----堆加速迪杰斯特拉

目录

堆加速迪杰斯特拉

暴力递归

汉诺塔

打印子序列

打印字符串的全排列

两个绝顶聪明的人

逆序栈

转换结果多少种

背包问题


堆加速迪杰斯特拉

原来算法无法用堆是因为系统所提供的堆不支持堆内元素改变后还能维持堆结构,需要人为改写堆来维持堆结构。 用额外的哈希表来记录堆中节点的下标,如果更新节点时有更小的值,就往上窜(在交换方法中也对哈希表中保存的下标进行修改),没有加入过这个节点就创建记录。

package com.wtp.基础.图.最短路径;
​
import java.util.HashMap;
​
import com.wtp.基础.图.图结构.Edge;
import com.wtp.基础.图.图结构.Node;
​
public class 堆加速 {
​
    public static class NodeRecord{
        Node node;
        int distance;
        
        public NodeRecord(Node node,int distance) {
            this.node = node;
            this.distance = distance;
        }
    }
    
    public static class NodeHeap{
        
        private Node[] nodes;
        private HashMap<Node,Integer> heapIndexMap;
        private HashMap<Node,Integer> distanceMap;
        private int size;
        
        public NodeHeap(int size) {
            nodes = new Node[size];
            heapIndexMap = new HashMap<>();
            distanceMap = new HashMap<>();
            size = 0;
        }
        
        
        //添加或更新或忽视
        public void addOrUpdateOrIgnore(Node node, int distance) {
            
            if(inHeap(node)) {
                distanceMap.put(node, Math.min(distanceMap.get(node), distance));
                insertHeapify(node,heapIndexMap.get(node));
            }
            if(!isEntered(node)) {
                heapIndexMap.put(node, size);
                distanceMap.put(node, distance);
                nodes[size] = node;
                insertHeapify(node,size++);
            }
        }
        
        public NodeRecord pop() {
            NodeRecord nodeRecord = new NodeRecord(nodes[0],distanceMap.get(nodes[0]));
            swap(0,size - 1);
            distanceMap.remove(nodes[size - 1]);
            heapIndexMap.put(nodes[size - 1], -1);
            nodes[size - 1] = null;
            heapify(0, --size);
            return nodeRecord;
        }
​
        
        private void insertHeapify(Node node, Integer index) {
            while(distanceMap.get(nodes[index]) < distanceMap.get(nodes[(index - 1) / 2])) {
                swap(index,(index - 1) / 2);
                index = (index - 1) / 2;
            }   
        }
​
        private void heapify(int index,int size) {
            int left = index * 2 + 1;
            while(left < size) {
                int minIndex = left + 1 < size && 
                        distanceMap.get(nodes[left + 1]) < distanceMap.get(nodes[left]) ?
                        left + 1 : left;
                
                minIndex = distanceMap.get(nodes[index]) < distanceMap.get(nodes[minIndex]) ?
                        index : minIndex;
                
                if(minIndex == index) {
                    return;
                }
                swap(minIndex,index);
                index = minIndex;
                left = 2 * index + 1;
            }
        }
​
        
        
        public boolean isEmpty() {
            return size == 0;
        }
        
        //判断node是否进来过堆
        private boolean isEntered(Node node) {
            return heapIndexMap.containsKey(node);
        }
        
        //判断node是否在堆上 -1表示进来过但弹出了
        private boolean inHeap(Node node) {
            return isEntered(node) && heapIndexMap.get(node) != -1;
        }
        
        private void swap(int index1,int index2) {
            heapIndexMap.put(nodes[index1], index2);
            heapIndexMap.put(nodes[index2], index1);
            
            Node temp = nodes[index1];
            nodes[index1] = nodes[index2];
            nodes[index2] = temp;
        }
    }
    
    public static HashMap<Node,Integer> d2(Node head,int size){
        
        NodeHeap nodeHeap = new NodeHeap(size);
        nodeHeap.addOrUpdateOrIgnore(head,0);
        HashMap<Node,Integer> res = new HashMap<>();
        
        while(!nodeHeap.isEmpty()) {
            NodeRecord record = nodeHeap.pop();
            Node cur = record.node;
            int distance = record.distance;
            for(Edge edge : cur.edges) {
                nodeHeap.addOrUpdateOrIgnore(edge.to, edge.weight + distance);
            }
            res.put(cur, distance);
        }
        
        return res;
        
    }
}
​

暴力递归

尝试时不必想全局,只要局部下拆分的决策正确,整体就正确

汉诺塔

先将上面n-1个盘子从start移到other,再将最后一个盘中从start移到end,最后将n-1个盘中从other移到end

public static void main(String[] args) {
        process(2,'左','右','中');
    }
    
    public static void process(int n,char from,char to,char other) {
        if(n == 1) {
            System.out.println(from + "=>" + to);
            return;
        }
        process(n - 1,from,other,to);
        System.out.println(from + "=>" + to);
        process(n - 1,other,to,from);
    }
打印子序列

分为要和不要各走一条路

package com.wtp.基础.暴力递归;
​
import java.util.ArrayList;
​
public class 打印子序列 {
​
    public static void main(String[] args) {
        
        String s = "abc";
        
        process(s.toCharArray(),0);
        for(String str : res) {
            System.out.println(str);
        }
        
        //process2(s.toCharArray(),0);
    }
    
    public static void process2(char[] str,int i) {
        if(i == str.length) {
            System.out.println(String.valueOf(str));
            return;
        }
        process2(str,i+1);
        char temp = str[i];
        str[i] = 0;
        process2(str,i+1);
        str[i] = temp;
    }
    
    static ArrayList<String> res = new ArrayList<>();
    static StringBuffer sb = new StringBuffer();
    public static void process(char[] chs,int i) {
        
        if(i == chs.length) {
            res.add(sb.toString());
            return;
        }
        
        sb.append(chs[i]);
        process(chs,i + 1);
        sb.deleteCharAt(sb.toString().length() - 1);
        process(chs,i + 1);
        
    }
}
​
打印字符串的全排列

在字符串中可能有相同的字母,要进行去重操作。 定义一个boolean类型的检查数组,在for循环中从后面没选过的字母放当前位置时判断是否在这个位置上放过相同的字母,没放过才放。 在程序中去重可以少走路(分支限界),比收集完所有可能再去重要快。指标没有优化,常数优化

package com.wtp.基础.暴力递归;
​
import java.util.TreeMap;
import java.util.TreeSet;
​
public class 打印字符串的全排列 {
​
    public static void main(String[] args) {
        
        String s = "abc";
        //process(s,0,new boolean[s.length()]);
        process(s.toCharArray(),0);
        
        for(String str : res) {
            System.out.println(str);
        }
    }
    
    public static void process(char[] chs,int i) {//走完所有可能后洗数据
        
        if(i == chs.length) {
            res.add(String.valueOf(chs));
            return;
        }
        for(int j = i; j < chs.length;j++) {
            swap(chs,i,j);
            process(chs,i + 1);
            swap(chs,i,j);          
        }
    }
    
    public static void swap(char[] chs,int i,int j) {
        char c = chs[i];
        chs[i] = chs[j];
        chs[j] = c;
    }
    
    static StringBuffer sb = new StringBuffer();
    static TreeSet<String> res = new TreeSet<>();
    public static void process(String str,int i,boolean[] record) {
        
        if(sb.length() == str.length()) {
            res.add(sb.toString());
            return;
        }
        for(int j = 0;j < str.length();j++) {
            if(!record[j]) {
                sb.append(str.charAt(j));
                record[j] = true;
                
                process(str,j,record);
                sb.deleteCharAt(sb.toString().length() - 1);
                record[j] = false;
            }
        }
    }
}
​
//去重
public static void process(char[] chs,int i) {//确定第i个位置
        
        if(i == chs.length) {
            res.add(String.valueOf(chs));
            return;
        }
        boolean[] visit = new boolean[26]; 
        for(int j = i; j < chs.length;j++) {
            if(!visit[chs[j] - 'a']) {//剪枝 重复的就不走了
                visit[chs[j] - 'a'] = true;//确定第i个位置时 chs[j]若出现过就不继续了
                swap(chs,i,j);
                process(chs,i + 1);
                swap(chs,i,j);  
            }
                    
        }
    }
两个绝顶聪明的人
package com.wtp.基础.暴力递归;
​
public class 两个绝顶聪明的人 {
​
    public static void main(String[] args) {
        
    }
    
    public static int process(int[] arr) {
        
        if(arr == null || arr.length == 0) {
            return 0;
        }
        return Math.max(f(arr,0,arr.length - 1), s(arr,0,arr.length - 1));//先手和后手谁赢
    }
    
    public static int f(int[] arr,int l,int r) {
        if(l == r) {
            return arr[l];
        }
        return Math.max(arr[l] + s(arr,l+1,r), arr[r] + s(arr,l,r-1));//先手选最大
    }
    
    public static int s(int[] arr,int l,int r) {
        if(l == r) {
            return 0;
        }
        return Math.min(f(arr,l+1,r), f(arr,l,r-1));//后手在该范围内先手 看似两种可能实则先手之人留下了最坏的选择
    }
}
​
逆序栈

不使用其他结构,用栈将一个栈中元素逆序

package com.wtp.基础.暴力递归;
​
import java.util.Stack;
​
public class 逆序栈 {
​
    public static void main(String[] args) {
        
        Stack<Integer> stack = new Stack<>();
        for(int i = 0;i < 10;i++) {
            stack.push(i);
        }
        reverse(stack);
        while(!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }
    
    public static void reverse(Stack<Integer> stack) {
        if(stack.isEmpty()) {
            return;
        }
        int i = f(stack);
        reverse(stack);
        stack.push(i);      
    }
    
    //弹出栈中最底的元素
    public static int f(Stack<Integer> stack) {
        int result = stack.pop();
        if(stack.isEmpty()) {
            return result;
        }else {
            int last = f(stack);
            stack.push(result);
            return last;
        }
    }
}
​
转换结果多少种

给一个数字序列,1对应a,2对应b......26对应z,问有多少种转换结果

package com.wtp.基础.暴力递归;
​
public class 转换结果 {
​
    public static void main(String[] args) {
        
        System.out.println(process("12".toCharArray(),0));
    }
    
    public static int process(char[] chs,int i) {
        
        if(i == chs.length) {
            return 1;
        }
        if(chs[i] == '0') {
            return 0;
        }
        
        int res = process(chs,i+1);
        if(chs[i] == '1' && i + 1 < chs.length) {
            res += process(chs,i+2);
        }
        if(chs[i] == '2' && (i + 1) < chs.length && chs[i + 1] >= '0' && chs[i+1] <= '6') {
            res += process(chs,i+2);
        }
        return res;
    }
}
​
背包问题
package com.wtp.基础.暴力递归;
​
public class 最大价值_背包问题 {
​
    public static void main(String[] args) {
        
    }
    
    public static int process(int i,int curw,int curv,int bag,int[] w,int[] v) {
        
        if(curw > bag) {
            return 0;   
        }
        if(i == w.length) {
            return curv;
        }
        return Math.max(process(i+1,curw+w[i],curv+v[i],bag,w,v),
                process(i+1,curw,curv,bag,w,v));    
    }
}
​
  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值