(day 7)持续学习:暴力递归

243 阅读1分钟

Dijkstra算法优化

原Dijkstra中,从distanceMap中获取未被固定的点时,我们通过遍历比较拿到最小的距离最小的节点,这里的时间复杂度是O(N^2),我们可以利用小根堆将其优化为 O(n*logn)

	public static Map<Node<Integer, Integer>, Integer> dijkstra2(Graph<Integer, Integer> graph, Node<Integer, Integer> startNode) {

		NodeHeap nodeHeap = new NodeHeap(graph.getNodes().size());

		NodeRecord originPoint = new NodeRecord(startNode, 0);
		nodeHeap.addOrUpdateOrIgnore(originPoint);

		while (nodeHeap.size != 0){

			NodeRecord<Integer, Integer> topRecord = nodeHeap.pop();

			int jumpNodeDistance = topRecord.distance;

			for(Edge<Integer> edge : topRecord.node.getEdges()){

				NodeRecord<Integer, Integer> neighborNode = new NodeRecord(edge.getTo(), jumpNodeDistance + edge.getWeight());

				nodeHeap.addOrUpdateOrIgnore(neighborNode);
			}
		}

		return  nodeHeap.distanceMap;

	}

	static class NodeRecord<N, E>{

		Node<N, E> node;

		int distance;

		public NodeRecord(Node node, int distance){
			this.node = node;

			this.distance = distance;
		}
	}
	/**
	 * 小根堆
	 */
	static class NodeHeap{
		//实际节点的堆
		NodeRecord<Integer, Integer>[] nodes;
		//堆中  node对应的下标
		Map<Node<Integer, Integer>, Integer> nodeIndexMap;
		Map<Node<Integer, Integer>, Integer> distanceMap;
		//堆中生效的节点数量
		int size;
		public NodeHeap(int size){
			this.nodes = new NodeRecord[size];
			this.nodeIndexMap = new HashMap<>();
			this.distanceMap = new HashMap<>();
			this.size = 0;
		}
		public NodeRecord pop(){
			if(size == 0){
				return null;
			}
			NodeRecord topNode = this.nodes[0];
			this.nodes[0] = this.nodes[size-1];
			size--;
			int index = 0;
			while (index*2+1 < size){
				if(nodes[index].distance > nodes[index*2 +1].distance){
					index = index*2+1;
					continue;
				}else if((index*2 + 2) < size && nodes[index].distance > nodes[index*2 +2].distance){
					index = index*2+2;
					continue;
				}else {
					break;
				}
			}
			swap(0, index);
			nodeIndexMap.put(topNode.node, -1);
			return topNode;
		}
		public void addOrUpdateOrIgnore(NodeRecord nodeRecord){
			if(!nodeIndexMap.containsKey(nodeRecord.node)){
				//节点原本不存在,新增节点到小根堆内
				addNode(nodeRecord);
			}else if(nodeIndexMap.get(nodeRecord.node) == -1){
				return;
			}else{
				int distance = distanceMap.get(nodeRecord.node);
				if(distance > nodeRecord.distance){
					distanceMap.put(nodeRecord.node, nodeRecord.distance);
				}
			}
		}

		private void addNode(NodeRecord nodeRecord){
			int index = size;
			nodes[index] = nodeRecord;
			size++;

			while (nodes[index].distance < nodes[(index-1)/2].distance){
				NodeRecord parent = nodes[(index-1)/2];
				if(nodeRecord.distance < parent.distance){
					NodeRecord tem = parent;
					nodes[(index-1)/2] = nodes[index];
					nodes[index] = tem;
					index = (index -1)/2;
				}else{
					break;
				}
			}
			distanceMap.put(nodeRecord.node, nodeRecord.distance);
			nodeIndexMap.put(nodeRecord.node, index);
		}

		private void swap(int i, int j){
			nodeIndexMap.put( this.nodes[i].node, j);
			nodeIndexMap.put(this.nodes[j].node, i);
			NodeRecord tmp = this.nodes[i];
			this.nodes[i] = this.nodes[j];
			this.nodes[j] = tmp;
		}
	}

汉诺塔问题

遥想当年读书的时候,学到汉诺塔问题的时候,总是感觉那么的神奇不得这个思想的要领,只能死记硬背。

如今重新学习,会把它和“冰箱塞大象问题”联想在一块儿。那么,冰箱塞大象,具体分几部呢?3步,将冰箱打开,把大象放进去,关上冰箱。

那么,继续问,把长颈鹿塞进冰箱分几步呢?4步:把冰箱打开,把大象拿出来,把长颈鹿塞进去,关上冰箱门。

汉诺塔问题和这个尤为相似,主要思想就是我先忽略掉你的细节,而是从大问题本身开始。将大问题从思维上对它进行拆解,拆解成相同的子问题,而这些子问题可以通过谜之步骤进行完成。

在汉诺塔问题里面,我们将n个汉诺塔的问题拆解成。

1)将上n-1个汉诺塔从“原点”移动到“临时点”上

2)然后将第n个汉诺塔,从“原点”上移动到“目标”上

3)将在B上的n-1个汉诺塔,从“临时点”上移动到“目标点”上。

然后,将n-1个汉诺塔的移动视为一个新整体问题,重复1)、2)、3)即可

有3个汉诺塔棋子,有3个干A\B\C,将棋子从A移动到C去。步骤如下:

hanoi 1 from A move to C

hanoi 2 from A move to B

hanoi 1 from C move to B

hanoi 3 from A move to C

hanoi 1 from B move to A

hanoi 2 from B move to C

hanoi 1 from A move to C

public static void hanoi(int n, String origin, String target, String temp){

    if(n<=1){
        System.out.println("hanoi " + n + " from " + origin + " move to " + target);
        return;
    }

    //1)将上n-1个汉诺塔从“原点”移动到“临时点”上;
    hanoi(n-1, origin, temp, target);

//		2)然后将第n个汉诺塔,从“原点”上移动到“目标”上
    System.out.println("hanoi " + n + " from " + origin + " move to " + target);

//		3)将在B上的n-1个汉诺塔,从“临时点”上移动到“目标点”上。
    hanoi(n-1, temp, target, origin);

}

给定一个栈,请逆序这个栈

给你个栈,栈有n个元素,请讲栈内元素逆序。

如:栈底到栈顶元素有: 1、2、3、4、5 。逆序后,栈底到栈顶:5、4、3、2、1

要求:不使用其他额外的数据结构,利用递归将栈逆序。

思路:将栈底元素拿出来,然后放到栈顶。


	public static void reverse(Stack<Integer> stack){

		if(stack.empty()){
			return;
		}

		int i = getLastElement(stack);
		reverse(stack);
		stack.push(i);

	}

	public static Integer getLastElement(Stack<Integer> stack){

		Integer i = stack.pop();
		if(stack.empty()){
			return i;
		}else{

			Integer j = getLastElement(stack);
			stack.push(i);
			return j;
		}
	}