刷题DAY10

题目一

奖励自己一个手撕并查集

class Node{
    int value;
    public Node(int v) {
        value = v;
    }
}
class unionfind{
    HashMap<Integer, Node> nodes = new HashMap<Integer, Node>();//用来保存所有节点 你得通过value找到对应点
    HashMap<Node, Node> father = new HashMap<Node, Node>();//所有节点对应的父节点
    HashMap<Node, Integer> size = new HashMap<Node, Integer>();//保存每个节点对应的 这一条的 size
    
    public void add(int [] arr) {//初始化并查集
        for(int i = 0;i<arr.length;i++) {
           Node node = new Node(arr[i]);
           nodes.put(arr[i],node);
           father.put(node, node);//每个节点的父亲都是它自己
           size.put(node, 1);//每个父亲的为头的串 长度只有1 只需要记录父节点的长度就行了 其他的都是冗余的
        }
    }
    public void union(Node node1,Node node2) {//肯定是吧短的连在长的上
        Node fa1 = father.get(node1);
        Node fa2 = father.get(node2);
        int size1 = size.get(fa1);
        int size2 = size.get(fa2);
    /*    if(size1>=size2) {
            father.put(fa2, fa1);
            size.put(fa1,size1+size2);
            size.remove(fa2);
        }else {
            father.put(fa1, fa2);
            size.put(fa2,size1+size2);
            size.remove(fa1);
        }  没考虑相等点的情况 如果是同一个点的话 那么size会变成2 很明显不合理*/
        if(node1!=node2) {
            Node bigger = size1>size2?fa1:fa2;
            Node smaller = bigger==node1?node2:node1;
            father.put(smaller,bigger);
            size.put(bigger, size1+size2);
            size.remove(smaller);
        }
        
    }
    
    public Node findfather(Node cur) {
        Stack<Node> stack = new Stack<Node>();
        while(cur!=father.get(cur)){
            stack.add(cur);
            cur = father.get(cur);
        }
        while(!stack.isEmpty()) {
            father.put(stack.pop(), cur);
        }
        return cur;
    }
    public int getsize(Node node) {
        return size.get(father.get(node));
    }
    
}

题目二 

Dijkstra算法

class Node {
	public int value;
	public int in;
	public int out;
	public ArrayList<Node> nexts;
	public ArrayList<Edge> edges;

	public Node(int value) {
		this.value = value;
		in = 0;
		out = 0;
		nexts = new ArrayList<>();
		edges = new ArrayList<>();
	}
}
class Edge {
	public int weight;
	public Node from;
	public Node to;

	public Edge(int weight, Node from, Node to) {
		this.weight = weight;
		this.from = from;
		this.to = to;
	}

}
class NodeRecord {
	public Node node;
	public int distance;

	public NodeRecord(Node node, int distance) {
		this.node = node;
		this.distance = distance;
	}
}
class Myheap{
	Node [] nodes;
	HashMap<Node, Integer> indexMap;//对标一般堆结构中的 位置map  这里面没有的是 用值去找对应点(点本身压根没有值啊) 这个相当于有node了找位置 那有位置找点怎么办? 直接数组啊
	HashMap<Node, Integer> distanceMap;
	int size;
	
	public Myheap(int size) {
		this.size = size;
		nodes = new Node [size];
		indexMap = new HashMap<Node, Integer>();
		distanceMap =  new HashMap<Node, Integer>();
	}
	public void heapify(int pos) {
		
		int left = indexMap.get(pos)*2+1;
		
		while(left<size) {
			int smallest = left;
			if(left+1<size) {
				smallest = distanceMap.get(nodes[left])>distanceMap.get(nodes[left+1])?left+1:left;
			}
			if(distanceMap.get(nodes[pos])>distanceMap.get(nodes[smallest])) {
				swap(pos,smallest);
			}else {
				break;
			}
			pos = smallest;//pos = left;是不对的因为可能和left+1的换 所以是smallest
			left = smallest*2+1;
		}
	}
	public void insert(int pos) {
		while (distanceMap.get(nodes[pos]) < distanceMap.get(nodes[(pos - 1) / 2])) {//当pos为0时(无论是1 还是 2 再减1除以2都为零 所以无论是左边上来还是右边上来都会有这一步) 0-1/2还等于0 也就是说所以到0点的时候就一定等于 因为就是一个node
			swap(pos, (pos - 1) / 2);
			pos = (pos - 1) / 2;
		}
	}
	public void swap(Node node1,Node node2) {
		int pos1 = indexMap.get(node1);
		int pos2 = indexMap.get(node2);
		Node tmp = node1;
		node1 = node2;
		node2 = tmp;
		indexMap.put(node1, pos2);
		indexMap.put(node2, pos1);
	}
	public void swap(int pos1,int pos2) {
		indexMap.put(nodes[pos1], pos2);
		indexMap.put(nodes[pos2], pos1);
		Node tmp = nodes[pos1];
		nodes[pos1] = nodes[pos2];
		nodes[pos2] = tmp;
		
	}
	public boolean isentered(Node node) {//进过堆
		return indexMap.containsKey(node);
	}
	public boolean inheap(Node node) {//在堆中 区别就是 堆弹出的元素 就是进过堆 但是不在堆中
		return indexMap.containsKey(node)&&(indexMap.get(node)!=-1);//后面我们会看到 把弹出节点的位置(map)中变成-1 但是不删除它 来表示它进过堆 但是呢 又出去了
	}
	public NodeRecord pop() {
		NodeRecord record = new NodeRecord(nodes[0], distanceMap.get(nodes[0]));
		swap(0, size - 1);
		indexMap.put(nodes[size-1], -1);
		distanceMap.remove(nodes[size - 1]);//这个不比index 用不到了就删除了吧 不删除还影响找最小distance
		nodes[--size] = null;//破案了 这个数组中删除一个点 就把他换到最后 置空 然后size--(这个不能忘记)
		heapify(0);//把被交换的向下调整
		return record;
	}
	public void addorupdateorIgnore(Node node,int distance) {
		if(inheap(node)) {
			distanceMap.put(node,Math.min(distance, distanceMap.get(node)));
			insert(indexMap.get(node));
		}
		if(!isentered(node)) {
			nodes[size] = node; //注意 size只能在最后++ 要不这个size就不表示它的位置了
			indexMap.put(node, size);//只要给他加进去 之后位置的调整是insert的事
			distanceMap.put(node, distance);
			insert(size++);
		}
	}//在堆中更新 进过堆了但是被弹出就是判断完了 忽略 没进过堆add
     	
}


public static HashMap<Node, Integer> dijkstra(Node head,int size) {
		 HashMap<Node, Integer> res = new HashMap<Node, Integer>();
		 Myheap heap = new Myheap(size);
		 res.put(head, 0);
		 while(heap.size!=0) {
			 NodeRecord record = heap.pop();
			 Node node = record.node;
			 int distance = record.distance;
			 for(Edge edge:node.edges) {
				 heap.addorupdateorIgnore(edge.to, edge.weight+distance);//这个distance是 拿出的点的已积累路径 再加上到达当前点的权重(边上的另一头) 然后具体行为交给addorupdateorIgnore判断
			 }
			 res.put(node, distance); //对应的是 每次找一个最小的点(肯定是能到达的) 这个点看完之后就不再看了 所以把它弹出放进结果了(弹出就表示不要了)
		 }
		 return res;
	}

题目三

假设一个固定大小为W的窗口,依次划过arr,返回每一次滑出状况的最大值例如,arr=[4,3,5,4,3,3,6,7],W=3返回:[5,5,5,4,6,7]

这要是看不出来滑动窗口法就自裁罢

说一下思路 往右扩 就是如果满足从大到小 就正常加入 如果不满足 就从后往前删 直到可以满足了再加入

原理是啥呢 我们演示一遍

4 加入

3 加入

5 弹出4 3 加入

此时窗口正式形成

4 加入

左侧缩一个 看看这个位置上的数在不在窗口里 不在了已经弹出来 那不管了(所以窗口里面保存的是数组元素的位置)

3加入 

左侧缩一个 看看原来的在不在 不在 不管

3加入

左侧缩一个 看看原来的在不在 在 弹出...以此类推

每次这个窗口的第一个位置就是它的窗口最大值

原理是怎么回事呢 我们窗口中的元素的含义是:成为最大值的优先级 假如我们此时窗口数值为[7,4,3] 那就是说7是最优先成为最大的 然后是4... 当然这是正常情况 窗口后面的数不会坐以待毙

如果下一个数是8 那不好意4 3 在8存在的时间内都成不了最大值 最变态的是什么 这个8在4 3 的后面出现 4 3都弹出去也轮不到8 永无出头之日了这回(所以可以直接把不满足从大到小的都弹出去吧  那只要前面有小的 永远都不会成为最大值了看都不用看)

OK 我们开始coding

  public int[] maxSlidingWindow(int[] nums, int k) {
int length = nums.length;
		 int [] res = new int [length-k+1];
		 int index = 0;
		 /*Stack<Integer> stack = new Stack<Integer>();
		 int index = 0;
		 int R = 0;//窗口大小固定 所以有R就有L
		 for(;R<k;R++) {
			 while(!stack.isEmpty()&&nums[stack.peek()]<nums[R]) {
				 stack.pop();
			 }
			 stack.push(R);
		 } 不能用栈实现啊 那第一个值取不出来啊 */ 
		 LinkedList<Integer> list = new LinkedList<Integer>();
		 int R = 0;
		 for(;R<k;R++) {
			 while (!list.isEmpty()&&nums[list.peekLast()]<nums[R]) {//因为栈可以用双向链表实现 所以里面有栈的方法 这很合理
				list.pollLast();//不过pop弹出的是队首元素哦
			}
			 list.addLast(R);
		 }
		 res[index++]= nums[list.getFirst()];
		 while(R<length) {
			 while (!list.isEmpty()&&nums[list.peekLast()]<nums[R]) {
					list.pollLast();
				}
			 if(list.contains(R-k)) {//contains就是正常的是否包含某元素 但是remove是移除某位置元素
				 list.pollFirst();//因为R先向右移动了一个了
			 }
			 list.addLast(R++);
			 res[index++]= nums[list.getFirst()];//一定要放在左移和右扩之后啊 放中间肯定不对
			 
		 }
		 return res;
}

做完这道题 我最大的感受就是 虽然双向链表可以模拟实现栈 但是不要用它的栈方法 乱套 只用addFIrst addLast pollFirst polllast 对于到底是前面加入还是后面加入来说这就很清晰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值