数据结构与算法拾遗五

比较器

比较器常规用法
主要记住返回1则是第二个参数在前
返回-1则是第一个参数在前

	public static class Student {
		public String name;
		public int id;
		public int age;

		public Student(String name, int id, int age) {
			this.name = name;
			this.id = id;
			this.age = age;
		}
	}

	// 谁id小,谁放前!
	public static class IdComparator implements Comparator<Student> {

		// 如果返回负数,认为第一个参数应该排在前面
		// 如果返回正数,认为第二个参数应该排在前面
		// 如果返回0,认为谁放前面无所谓
		@Override
		public int compare(Student o1, Student o2) {
			if (o1.id < o2.id) {
				return -1;
			} else if (o2.id < o1.id) {
				return 1;
			} else {
				return 0;
			}
		}
	}
	
	// 谁age大,谁放前!
	public static class AgeComparator implements Comparator<Student> {

		// 如果返回负数,认为第一个参数应该排在前面
		// 如果返回正数,认为第二个参数应该排在前面
		// 如果返回0,认为谁放前面无所谓
		@Override
		public int compare(Student o1, Student o2) {
			if (o1.age < o2.age) {
				return 1;
			} else if (o2.age < o1.age) {
				return -1;
			} else {
				return 0;
			}
		}
	}

	public static void printArray(int[] arr) {
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}

	public static void printStudents(Student[] students) {
		for (int i = 0; i < students.length; i++) {
			System.out.println(students[i].name + ", " + students[i].id + ", " + students[i].age);
		}
	}

	public static void main(String[] args) {
		int[] arr = { 8, 1, 4, 1, 6, 8, 4, 1, 5, 8, 2, 3, 0 };
		printArray(arr);
		Arrays.sort(arr);
		printArray(arr);

		Student s1 = new Student("张三", 5, 27);
		Student s2 = new Student("李四", 1, 17);
		Student s3 = new Student("王五", 4, 29);
		Student s4 = new Student("赵六", 3, 9);
		Student s5 = new Student("左七", 2, 34);

		Student[] students = { s1, s2, s3, s4, s5 };
		printStudents(students);
		System.out.println("=======");
		Arrays.sort(students, new IdComparator());
		printStudents(students);
		System.out.println("=======");

		ArrayList<Student> arrList = new ArrayList<>();
		arrList.add(s1);
		arrList.add(s2);
		arrList.add(s3);
		arrList.add(s4);
		arrList.add(s5);
		for (Student s : arrList) {
			System.out.println(s.name + ", " + s.id + ", " + s.age);
		}
		System.out.println("=======");
		arrList.sort(new AgeComparator());
		for (Student s : arrList) {
			System.out.println(s.name + ", " + s.id + ", " + s.age);
		}

	}

比较器对于优先级队列的使用:
优先队列默认为小根堆,从小到大排序
队顶元素为最小值

	// 负,第一个参数在前
		// 正,第二个参数在前
		// 0, 谁放前都行
		@Override
		public int compare(Integer o1, Integer o2) {
			if (o1 < o2) {
				return 1;
			} else if (o1 > o2) {
				return -1;
			} else {
				return 0;
			}
		}

	}

	public static class Student {
		public String name;
		public int id;
		public int age;

		public Student(String name, int id, int age) {
			this.name = name;
			this.id = id;
			this.age = age;
		}
	}

	// 谁id大,谁放前!
	public static class IdComparator implements Comparator<Student> {

		// 如果返回负数,认为第一个参数应该排在前面
		// 如果返回正数,认为第二个参数应该排在前面
		// 如果返回0,认为谁放前面无所谓
		@Override
		public int compare(Student o1, Student o2) {
			if (o1.id < o2.id) {
				return 1;
			} else if (o2.id < o1.id) {
				return -1;
			} else {
				return 0;
			}
		}
	}

	public static void main(String[] args) {
		String str1 = "abc";
		String str2 = "b";
		//String之间的比较为字典序之间的比较 如下返回-1
		System.out.println(str1.compareTo(str2));
		PriorityQueue<Student> heap = new PriorityQueue<>(new IdComparator());
		Student s1 = new Student("张三", 5, 27);
		Student s2 = new Student("李四", 1, 17);
		Student s3 = new Student("王五", 4, 29);
		Student s4 = new Student("赵六", 3, 9);
		Student s5 = new Student("左七", 2, 34);
		heap.add(s1);
		heap.add(s2);
		heap.add(s3);
		heap.add(s4);
		heap.add(s5);
		System.out.println("=========");
		while (!heap.isEmpty()) {
			Student s = heap.poll();
			System.out.println(s.name + ", " + s.id + ", " + s.age);
		}
	}

当然也可以改成如下lambda的形式

      PriorityQueue<Student> heap = new PriorityQueue<>((Student o1, Student o2) ->o1.id > o2.id ? -1 : 1);
         PriorityQueue<Student> heap = new PriorityQueue<>((Student o1, Student o2) -> o2.id - o1.id);     

合并k个升序链表

题目链接:https://leetcode.cn/problems/merge-k-sorted-lists/

思路:将所有链表的头节点入优先队列,然后取出这个队列的头部元素(最小的),然后再把这个头部元素指向的下一个节点放入优先队列中。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
   
    //首先写一个比较器
    public static class ListNodeComparator implements Comparator<ListNode> {
        @Override
        public int compare(ListNode o1, ListNode o2) {
            return o1.val - o2.val;
        }
    }

    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null) {
            return null;
        }
        PriorityQueue<ListNode> heap = new PriorityQueue<>(new ListNodeComparator() );
        	for (int i = 0; i < lists.length; i++) {
			if (lists[i] != null) {
				heap.add(lists[i]);
			}
		}
        if(heap.isEmpty()) {
           return null;     
        }

        ListNode head = heap.poll();
        ListNode pre = head;
        if (pre.next != null) {
            heap.add(pre.next);
        }
        while (!heap.isEmpty()) {
            ListNode cur = heap.poll();
            pre.next = cur;
            pre = cur;
            if (cur.next != null) {
                heap.add(cur.next);
            }
        }

        return head;
    }
}

如上最多一次有M个根节点进入小根堆 然后,总共有N个节点
对于小根堆的操作为logM
然后对于节点是有N个,要出去进来N次那么时间复杂度则为N*logM

二叉树

二叉树前中后序遍历:

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

		public Node(int v) {
			value = v;
		}
	}

	public static void f(Node head) {
		if (head == null) {
			return;
		}
		// 1
		f(head.left);
		// 2
		f(head.right);
		// 3
	}

	// 先序打印所有节点
	public static void pre(Node head) {
		if (head == null) {
			return;
		}
		System.out.println(head.value);
		pre(head.left);
		pre(head.right);
	}

	public static void in(Node head) {
		if (head == null) {
			return;
		}
		in(head.left);
		System.out.println(head.value);
		in(head.right);
	}

	public static void pos(Node head) {
		if (head == null) {
			return;
		}
		pos(head.left);
		pos(head.right);
		System.out.println(head.value);
	}

	public static void main(String[] args) {
		Node head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.right.left = new Node(6);
		head.right.right = new Node(7);

		pre(head);
		System.out.println("========");
		in(head);
		System.out.println("========");
		pos(head);
		System.out.println("========");

	}

如上代码的递归序为:
1,2,4,4,4,2,5,5,5,2,1,3,6,6,6,3,7,7,7,3,1
前中后序遍历则是
前序遍历:第一次来到一个数
中序遍历:第二次来到一个数
后序遍历:第三次来到一个数

判断两棵树是否相等

直接通过先序遍历判断各节点即可:
题目链接: https://leetcode.cn/problems/same-tree/submissions/

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
  public boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null ^ q == null) {
            return false;
        }
        if (p == null && q == null) {
            return true;
        }

        return p.val == q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right);

    }
}
判断一棵树是否为镜面树

一棵树分两个分支,左边分支的左节点要和右边分支的右节点一样,
左边分支的右节点要和右边分支的左节点一样。
如下传入将根节点当成一个节点和他的对称节点,然后分别往这棵树的左右两个分支递归,
先找左边分支的左边节点是否和右边分支的右节点相等,再找左边分支的右边节点是否和左边分支的左节点相等。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {

        return isMirror(root, root);
    }

    public boolean isMirror(TreeNode p, TreeNode q) {
        if (p == null ^ q == null) {
            return false;
        }
        if (p == null && q == null) {
            return true;
        }

        return p.val == q.val && isMirror(p.left, q.right) && isMirror(p.right, q.left);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值