220311(二叉树)

1.二叉树

二叉树常用套路

树形dp套路

树形dp套路使用前提: 如果题目求解目标是S规则,则求解流程可以定成以每一个节点为头节点的子树在S规则下 的每一个答案,并且最终答案一定在其中

树形dp套路第一步: 以某个节点X为头节点的子树中,分析答案有哪些可能性,并且这种分析是以X的左子 树、X的右子树和X整棵树的角度来考虑可能性的

树形dp套路第二步根据第一步的可能性分析,列出所有需要的信息

树形dp套路第三步合并第二步的信息,对左树和右树提出同样的要求,并写出信息结构

树形dp套路第四步设计递归函数,递归函数是处理以X为头节点的情况下的答案。 包括设计递归的basecase,默认直接得到左树和右树的所有信息,以及把可能性做整 合,并且要返回第三步的信息结构这四个小步骤

 ★要有大局观的思维,把头节点设为x,然后再想想左子树和左子树要达到什么才能满足条件,再判断左右子树递归后需要返回什么给你

①判断是否是平衡二叉树

首先:设头节点为x,要想该树为平衡二叉树,左子树必须是平衡二叉树,右子树也必须是平衡二叉树且左子树的高度-右子树的高度不能大于1

然后:我们想想那这样需要什么才能形成递归,头节点需要知道左右节点什么

        a)知道左右子树是否为平衡二叉树

        b)知道左右子树的高度

public class Code06_IsBalancedTree {

	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
			this.value = data;
		}
	}

    //主函数
	public static boolean isBalanced(Node head) {
		return process(head).isBalanced;
	}

    //创建用于获取递归数据
	public static class ReturnType {
		public boolean isBalanced;
		public int height;

		public ReturnType(boolean isB, int hei) {
			isBalanced = isB;
			height = hei;
		}
	}

    //递归方法
	public static ReturnType process(Node x) {
		if (x == null) {
			return new ReturnType(true, 0);
		}
        //获取左子树的数据
		ReturnType leftData = process(x.left);
        //获取右子树的数据
		ReturnType rightData = process(x.right);
        //获取高度差
		int height = Math.max(leftData.height, rightData.height);
        //判断左右子树是否为平衡二叉树
		boolean isBalanced = leftData.isBalanced && rightData.isBalanced
				&& Math.abs(leftData.height - rightData.height) < 2;
        //放回递归数据
		return new ReturnType(isBalanced, height);
	}

}
	public static void process(Node node, LinkedList<Node> inOrderList) {
		if (node == null) {
			return;
		}
		process(node.left, inOrderList);
		inOrderList.add(node);
		process(node.right, inOrderList);
	}

 同种套路使用于搜索二叉树

首先左子树必须的搜索二叉树,右子树也必须是搜索二叉树,左子树的最大值不大于头节点的值,右子树的最小值不小于头节点的值

然后我们需要知道左右子树是否也为搜索二叉树,且我们需要知道左子树的最大值,右子树的最小值,我们需要取并集,故需要知道最大和最小值

 2.K算法

① 从最小的边开始查找,该边加上后判断有没有形成环状,没有则要这条边,有则不要这条边

②继续向下一条最小边进行查找,循环上步骤

 难点:使用并查集来判断是否形成环状

3.P算法:

4.堆排序:

1,先让整个数组都变成大根堆结构,建立堆的过程:

        1)从上到下的方法,时间复杂度为O(N*logN)

        2)从下到上的方法,时间复杂度为O(N)

2,把堆的最大值和堆末尾的值交换,然后减少堆的大小之后,再去调 整堆,一直周而复始,时间复杂度为O(N*logN)

3,堆的大小减小成0之后,排序完成

	public static void heapSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
        //变成大根堆
		for (int i = 0; i < arr.length; i++) {
			heapInsert(arr, i);
		}
        //定义边界
		int size = arr.length;
        //将最大值和最小值进行交换
        //size减少则,最大值已经定好了
		swap(arr, 0, --size);
        
		while (size > 0) {
            //循环将头节点放到下面
			heapify(arr, 0, size);
			swap(arr, 0, --size);
		}
	}

	public static void heapInsert(int[] arr, int index) {
         //当前节点大于父节点,则一直向上进行交换
		while (arr[index] > arr[(index - 1) / 2]) {
			swap(arr, index, (index - 1) /2);
			index = (index - 1)/2 ;
		}
	}

    //通过顶端的数下降形成新的大根堆
	public static void heapify(int[] arr, int index, int size) {
		int left = index * 2 + 1;
		while (left < size) {
            //left + 1为右节点,判断左右节点获取最大
			int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
            //与其父节点进行比较大小
			largest = arr[largest] > arr[index] ? largest : index;
            //如果最大已经是index则不用再执行了
			if (largest == index) {
				break;
			}
            //否则交换该节点和其父节点的位置
			swap(arr, largest, index);
            //对应的坐标节点变成当前最大的节点
			index = largest;
            //重新赋予其左节点的下标
			left = index * 2 + 1;
		}
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

难点:把数组变为大根堆

 荷兰国旗问题(快排partition的子问题):

思路:问题主要是将数分为三个部分,即等于1,大于1和小于1所以我们应该对此进行判断,我们对应创建两个区域,一个是左边小于1的区域,一个是右边大于1的区域

则主要步骤就慢慢出来了,对每一个数进行遍历,定义三个指针,两个分别指向最左和最右的位置,另一个指向当前数,遍历时进行数值判断,若该数

        ①小于1,则最左指针指向的数与该数进行交换,并且当前指针继续右移,左指针右移

        ②等于1,则继续右移即可

        ③大于1,则当前最右指针指向的数与该数进行交互,当前指针不需要右移动(因为是从头遍历,之前右指针所指向的数还未进行判断),右指针左移

public class Solution {

    public void sortColors(int[] nums) {
        int len = nums.length;
        if (len < 2) {
            return;
        }
        int zero = 0;
        int two = len;
        int i = 0;
        while (i < two) {
            if (nums[i] == 0) {
                swap(nums, i, zero);
                zero++;
                i++;
            } else if (nums[i] == 1) {
                i++;
            } else {
                two--;
                swap(nums, i, two);
            }
        }
    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

5.快排:

1)在数组范围中,等概率随机选一个数作为划分值,然后把数组通过荷兰国旗问题分 成三个部分: 左侧划分值

2)对左侧范围和右侧范围,递归执行

3)时间复杂度为O(N*logN)

public static void quickSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		quickSort(arr, 0, arr.length - 1);
	}

	public static void quickSort(int[] arr, int l, int r) {
		if (l < r) {
            //获取随机数
			swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
			int[] p = partition(arr, l, r);
			quickSort(arr, l, p[0] - 1);
			quickSort(arr, p[1] + 1, r);
		}
	}

	public static int[] partition(int[] arr, int l, int r) {
		int less = l - 1;
		int more = r;
		while (l < more) {
			if (arr[l] < arr[r]) {
				swap(arr, ++less, l++);
			} else if (arr[l] > arr[r]) {
				swap(arr, --more, l);
			} else {
				l++;
			}
		}
		swap(arr, more, r);
		return new int[] { less + 1, more };
	}

	public static void swap(int[] arr, int i, int j) {
		int tmp = arr[i];
		arr[i] = arr[j];
		arr[j] = tmp;
	}

6.图的广搜

public static void bfs(Node node) {
		if (node == null) {
			return;
		}
        //广搜都用队列
		Queue<Node> queue = new LinkedList<>();
        //使用set判断,避免重复加入队列
		HashSet<Node> map = new HashSet<>();
		queue.add(node);
		map.add(node);
		while (!queue.isEmpty()) {
			Node cur = queue.poll();
			System.out.println(cur.value);
            //对当前节点的所有连通节点进行遍历
			for (Node next : cur.nexts) {
                //如果set里面还没有next则加入
				if (!map.contains(next)) {
					map.add(next);
					queue.add(next);
				}
			}
		}
	}

7.图的深搜

public static void dfs(Node node) {
		if (node == null) {
			return;
		}
        //深搜使用栈
		Stack<Node> stack = new Stack<>();
        //同理,避免重复加入队列
		HashSet<Node> set = new HashSet<>();
		stack.add(node);
		set.add(node);
		System.out.println(node.value);
		while (!stack.isEmpty()) {
			Node cur = stack.pop();
            //对当前节点的所有下一个节点进行遍历
			for (Node next : cur.nexts) {
				if (!set.contains(next)) {
                    //如果没有则把当前节点重新压入栈,再将此下一个节点叶压入
                    //则下一个遍历时是对next节点进行遍历,重复如下,则能实现深度遍历
					stack.push(cur);
					stack.push(next);
					set.add(next);
					System.out.println(next.value);
					break;
				}
			}
		}
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值