Amazon High Frequent 9 problems
1. Maximum Subtree
Given a binary tree, find the subtree with maximum sum. Return the root of the subtree. It's guaranteed that there is only one subtree with maximum sum and the given binary tree is not an empty tree. Example Given a binary tree: 1 / \ -5 2 / \ / \ 0 3 -4 -5 return the node with value 3.
思路:Divide Conquer,保存全局sum和node。
1 public class Solution { 2 int maxSum = Integer.MIN_VALUE; 3 TreeNode node = null; 4 /** 5 * @param root the root of binary tree 6 * @return the maximum weight node 7 */ 8 public TreeNode findSubtree(TreeNode root) { 9 if (root == null) { 10 return null; 11 } 12 // Write your code here 13 findMaxSubtree(root); 14 return node; 15 } 16 public int findMaxSubtree(TreeNode root) { 17 if (root == null) { 18 return 0; 19 } 20 int sum = root.val; 21 sum += findMaxSubtree(root.left); 22 sum += findMaxSubtree(root.right); 23 if (node == null || sum > maxSum) { 24 maxSum = sum; 25 node = root; 26 } 27 return sum; 28 } 29 }
2. Rectangle Overlap
Given two rectangles, find if the given two rectangles overlap or not. l1: Top Left coordinate of first rectangle. r1: Bottom Right coordinate of first rectangle. l2: Top Left coordinate of second rectangle. r2: Bottom Right coordinate of second rectangle. Example Given l1 = [0, 8], r1 = [8, 0], l2 = [6, 6], r2 = [10, 0], return true Given l1 = [0, 8], r1 = [8, 0], l2 = [9, 6], r2 = [10, 0], return `false
思路:直接判断相交逻辑比较复杂,从反面入手,判断哪些情况肯定不相交,剩下的就相交了。注意两个矩形个别点相交也算是相交。
1 /** 2 * Definition for a point. 3 * class Point { 4 * public int x, y; 5 * public Point() { x = 0; y = 0; } 6 * public Point(int a, int b) { x = a; y = b; } 7 * } 8 */ 9 10 public class Solution { 11 /** 12 * @param l1 top-left coordinate of first rectangle 13 * @param r1 bottom-right coordinate of first rectangle 14 * @param l2 top-left coordinate of second rectangle 15 * @param r2 bottom-right coordinate of second rectangle 16 * @return true if they are overlap or false 17 */ 18 public boolean doOverlap(Point l1, Point r1, Point l2, Point r2) { 19 // Write your code here 20 if (l2.x > r1.x || r2.x < l1.x) { 21 return false; 22 } 23 if (l2.y < r1.y || r2.y > l1.y) { 24 return false; 25 } 26 return true; 27 } 28 }
3. Longest Palindrome
Given a string which consists of lowercase or uppercase letters, find the length of the longest palindromes that can be built with those letters. This is case sensitive, for example "Aa" is not considered a palindrome here. Notice Assume the length of given string will not exceed 1010. Example Given s = "abccccdd" return 7 One longest palindrome that can be built is "dccaccd", whose length is 7.
思路:用Map统计每个单词出现的次数,次数为偶数的的直接加入总长度,次数为奇数的将次数 - 1加入总长度,最后还要看次数是否有奇数次,有的话总长度多加1,否则不加。
1 public class Solution { 2 /** 3 * @param s a string which consists of lowercase or uppercase letters 4 * @return the length of the longest palindromes that can be built 5 */ 6 public int longestPalindrome(String s) { 7 // Write your code here 8 if (s == null || s.length() == 0) { 9 return 0; 10 } 11 Map<Character, Integer> map = new HashMap<>(); 12 for (int i = 0; i < s.length(); i++) { 13 char c = s.charAt(i); 14 if (map.containsKey(c)) { 15 map.put(c, map.get(c) + 1); 16 } else { 17 map.put(c, 1); 18 } 19 } 20 int maxLength = 0; 21 int oddCount = 0; 22 for (Character c : map.keySet()) { 23 int count = map.get(c); 24 if (count % 2 == 0) { 25 maxLength += count; 26 } else { 27 maxLength += count - 1; 28 oddCount++; 29 } 30 } 31 return oddCount > 0 ? maxLength + 1 : maxLength; 32 } 33 }
4. Window Sum
Window Sum Given an array of n integer, and a moving window(size k), move the window at each iteration from the start of the array, find the sum of the element inside the window at each moving. Example For array [1,2,7,8,5], moving window size k = 3. 1 + 2 + 7 = 10 2 + 7 + 8 = 17 7 + 8 + 5 = 20 return [10,17,20]
思路:比较简单,加前一个数字减后一个数,依次循环即可。
1 public class Solution { 2 /** 3 * @param nums a list of integers. 4 * @return the sum of the element inside the window at each moving. 5 */ 6 public int[] winSum(int[] nums, int k) { 7 // write your code here 8 if (nums == null || nums.length == 0 || k <= 0 || nums.length < k) { 9 return new int[0]; 10 } 11 int[] results = new int[nums.length - k + 1]; 12 for (int i = 0; i < k; i++) { 13 results[0] += nums[i]; 14 } 15 for (int i = 1; i < nums.length - k + 1; i++) { 16 results[i] = results[i - 1] - nums[i - 1] + nums[i - 1 + k]; 17 } 18 return results; 19 } 20 }
5. Copy List with Random Pointer
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list.
思路:方法一 -- 建一个Map存储新老节点的映射关系,然后一次遍历老节点,进行新节点的next指针和random指针的复制。
方法二 -- 1, 复制节点。将原链表的每个节点都复制一份新节点插入到相应老节点后面。2. 复制random指针。遍历修改后的链表,将老节点的random连接关系复制给新节点的random。3. 建立两个dummy节点分别串起老节点和新节点,分离两个链表。最后返回得到的新链表。
1 /** 2 * Definition for singly-linked list with a random pointer. 3 * class RandomListNode { 4 * int label; 5 * RandomListNode next, random; 6 * RandomListNode(int x) { this.label = x; } 7 * }; 8 */ 9 public class Solution { 10 /** 11 * @param head: The head of linked list with a random pointer. 12 * @return: A new head of a deep copy of the list. 13 */ 14 public RandomListNode copyRandomList(RandomListNode head) { 15 // write your code here 16 if (head == null) { 17 return null; 18 } 19 Map<RandomListNode, RandomListNode> map = 20 new HashMap<RandomListNode, RandomListNode>(); 21 RandomListNode dummy = new RandomListNode(0); 22 RandomListNode cur = dummy; 23 RandomListNode newNode = null; 24 while (head != null) { 25 if (map.containsKey(head)) { 26 newNode = map.get(head); 27 } else { 28 newNode = new RandomListNode(head.label); 29 map.put(head, newNode); 30 } 31 cur.next = newNode; 32 cur = cur.next; 33 if (head.random != null) { 34 if (map.containsKey(head.random)) { 35 newNode.random = map.get(head.random); 36 } else { 37 RandomListNode temp = new RandomListNode(head.random.label); 38 map.put(head.random, temp); 39 newNode.random = temp; 40 } 41 } 42 head = head.next; 43 } 44 return dummy.next; 45 } 46 }
1 /*第一遍扫的时候巧妙运用next指针, 开始数组是1->2->3->4 。 然后扫描过程中 先建立copy节点 1->1`->2->2`->3->3`->4->4`, 然后第二遍copy的时候去建立边的copy, 拆分节点, 一边扫描一边拆成两个链表,这里用到两个dummy node。第一个链表变回 1->2->3 , 然后第二变成 1`->2`->3` */ 2 //No HashMap version 3 public class Solution { 4 private void copyNext(RandomListNode head) { 5 while (head != null) { 6 RandomListNode newNode = new RandomListNode(head.label); 7 newNode.random = head.random; 8 newNode.next = head.next; 9 head.next = newNode; 10 head = head.next.next; 11 } 12 } 13 14 private void copyRandom(RandomListNode head) { 15 while (head != null) { 16 if (head.next.random != null) { 17 head.next.random = head.random.next; 18 } 19 head = head.next.next; 20 } 21 } 22 23 private RandomListNode splitList(RandomListNode head) { 24 RandomListNode newHead = head.next; 25 while (head != null) { 26 RandomListNode temp = head.next; 27 head.next = temp.next; 28 head = head.next; 29 if (temp.next != null) { 30 temp.next = temp.next.next; 31 } 32 } 33 return newHead; 34 } 35 36 public RandomListNode copyRandomList(RandomListNode head) { 37 if (head == null) { 38 return null; 39 } 40 copyNext(head); 41 copyRandom(head); 42 return splitList(head); 43 } 44 }
6. K Closest Points
Given some points and a point origin in two dimensional space, find k points out of the some points which are nearest to origin. Return these points sorted by distance, if they are same with distance, sorted by x-axis, otherwise sorted by y-axis. Example Given points = [[4,6],[4,7],[4,4],[2,5],[1,1]], origin = [0, 0], k = 3 return [[1,1],[2,5],[4,4]]
思路:建立大根堆,存储距离最近的k个点,距离大的在前,距离小的在后,以便于随时更新大根堆。
1 /** 2 * Definition for a point. 3 * class Point { 4 * int x; 5 * int y; 6 * Point() { x = 0; y = 0; } 7 * Point(int a, int b) { x = a; y = b; } 8 * } 9 */ 10 public class Solution { 11 public Point global_origin = null; 12 /** 13 * @param points a list of points 14 * @param origin a point 15 * @param k an integer 16 * @return the k closest points 17 */ 18 public Point[] kClosest(Point[] points, Point origin, int k) { 19 // Write your code here 20 if (k <= 0 || points.length < k) { 21 return new Point[0]; 22 } 23 global_origin = origin; 24 PriorityQueue<Point> pq 25 = new PriorityQueue<>(k, new Comparator<Point>() { 26 public int compare(Point a, Point b) { 27 int distance = getDistance(b, global_origin) 28 - getDistance(a, global_origin); 29 if (distance == 0) { 30 distance = b.x - a.x; 31 } 32 if (distance == 0) { 33 distance = b.y - a.y; 34 } 35 return distance; 36 } 37 }); 38 for (int i = 0; i < points.length; i++) { 39 pq.offer(points[i]); 40 if (pq.size() > k) { 41 pq.poll(); 42 } 43 } 44 k = pq.size(); 45 Point[] kPoints = new Point[k]; 46 for (int i = k - 1; i >= 0; i--) { 47 kPoints[i] = pq.poll(); 48 } 49 return kPoints; 50 } 51 public int getDistance(Point a, Point b) { 52 return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); 53 } 54 }
7. High Five
There are two properties in the node student id and scores, to ensure that each student will have at least 5 points, find the average of 5 highest scores for each person. Example Given results = [[1,91],[1,92],[2,93],[2,99],[2,98],[2,97],[1,60],[1,58],[2,100],[1,61]] Return
思路:建立Map存储学生id和他的各个科目的得分,满5就保留下得分最高的前五个分数。最后依次输出每个学生前五高分数的平均分。
1 /** 2 * Definition for a Record 3 * class Record { 4 * public int id, score; 5 * public Record(int id, int score){ 6 * this.id = id; 7 * this.score = score; 8 * } 9 * } 10 */ 11 public class Solution { 12 /** 13 * @param results a list of <student_id, score> 14 * @return find the average of 5 highest scores for each person 15 * Map<Integer, Double> (student_id, average_score) 16 */ 17 public Map<Integer, Double> highFive(Record[] results) { 18 // Write your code here 19 Map<Integer, Double> map = new HashMap<>(); 20 Map<Integer, List<Integer>> hash = new HashMap<>(); 21 if (results == null || results.length == 0) { 22 return map; 23 } 24 for (Record record : results) { 25 if (!hash.containsKey(record.id)) { 26 hash.put(record.id, new ArrayList<Integer>()); 27 } 28 if (hash.get(record.id).size() < 5) { 29 hash.get(record.id).add(record.score); 30 } else { 31 int index = 0; 32 for (int i = 1; i < 5; i++) { 33 if (hash.get(record.id).get(i) 34 < hash.get(record.id).get(index)) { 35 index = i; 36 } 37 } 38 if (record.score > hash.get(record.id).get(index)) { 39 hash.get(record.id).set(index, record.score); 40 } 41 } 42 } 43 for (Integer num : hash.keySet()) { 44 int sum = 0; 45 for (int i = 0; i < hash.get(num).size(); i++) { 46 sum += hash.get(num).get(i); 47 } 48 map.put(num, (sum * 1.0) / hash.get(num).size()); 49 } 50 return map; 51 } 52 }
8. Course Schedule II
There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1] Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses. There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array. Example Given n = 2, prerequisites = [[1,0]] Return [0,1] Given n = 4, prerequisites = [1,0],[2,0],[3,1],[3,2]] Return [0,1,2,3] or [0,2,1,3]
思路:拓扑排序,先统计每个节点的入度,只有节点的入度为0方可入列。
1 public class Solution { 2 /** 3 * @param numCourses a total of n courses 4 * @param prerequisites a list of prerequisite pairs 5 * @return the course order 6 */ 7 public int[] findOrder(int numCourses, int[][] prerequisites) { 8 // Write your code here 9 if (numCourses == 0) { 10 return new int[0]; 11 } 12 int[] inDegree = new int[numCourses]; 13 List<List<Integer>> neighbors = new ArrayList<>(); 14 for (int i = 0; i < numCourses; i++) { 15 neighbors.add(new ArrayList<Integer>()); 16 } 17 for (int i = 0; i < prerequisites.length; i++) { 18 inDegree[prerequisites[i][0]]++; 19 neighbors.get(prerequisites[i][1]).add(prerequisites[i][0]); 20 } 21 Queue<Integer> queue = new LinkedList<>(); 22 int[] result = new int[numCourses]; 23 int count = 0; 24 for (int i = 0; i < numCourses; i++) { 25 if (inDegree[i] == 0) { 26 queue.offer(i); 27 result[count++] = i; 28 } 29 } 30 while (!queue.isEmpty()) { 31 int value = queue.poll(); 32 for (Integer neighbor : neighbors.get(value)) { 33 inDegree[neighbor]--; 34 if (inDegree[neighbor] == 0) { 35 queue.offer(neighbor); 36 result[count++] = neighbor; 37 } 38 } 39 } 40 if (count == numCourses) { 41 return result; 42 } else { 43 return new int[0]; 44 } 45 } 46 }
Follow up:Course Schedule
There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1] Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses? Example Given n = 2, prerequisites = [[1,0]] Return true Given n = 2, prerequisites = [[1,0],[0,1]] Return false
思路:拓扑排序,最后判断拓扑排序得到的节点数是否和原来节点数相同即可。(初始化每个节点的邻居不用写得这么复杂,用一个List<List<Integer>>存储就够,索引表示哪个节点,里面存放该节点的邻居)。
1 public class Solution { 2 /** 3 * @param numCourses a total of n courses 4 * @param prerequisites a list of prerequisite pairs 5 * @return true if can finish all courses or false 6 */ 7 public boolean canFinish(int numCourses, int[][] prerequisites) { 8 // Write your code here 9 if (numCourses == 0) { 10 return true; 11 } 12 Map<Integer, Integer> inDegree = new HashMap<>(); 13 Map<Integer, Set<Integer>> graph = 14 initializeGraph(numCourses, prerequisites); 15 for (int i = 0; i < numCourses; i++) { 16 for (Integer neighbor : graph.get(i)) { 17 if (!inDegree.containsKey(neighbor)) { 18 inDegree.put(neighbor, 1); 19 } else { 20 inDegree.put(neighbor, inDegree.get(neighbor) + 1); 21 } 22 } 23 } 24 Queue<Integer> queue = new LinkedList<>(); 25 int count = 0; 26 for (int i = 0; i < numCourses; i++) { 27 if (!inDegree.containsKey(i)) { 28 queue.offer(i); 29 count++; 30 } 31 } 32 while (!queue.isEmpty()) { 33 int value = queue.poll(); 34 for (Integer neighbor : graph.get(value)) { 35 inDegree.put(neighbor, inDegree.get(neighbor) - 1); 36 if (inDegree.get(neighbor) == 0) { 37 queue.offer(neighbor); 38 count++; 39 } 40 } 41 } 42 return count == numCourses; 43 } 44 public Map<Integer, Set<Integer>> initializeGraph(int numCourses, 45 int[][] prerequisites) { 46 Map<Integer, Set<Integer>> map = new HashMap<>(); 47 for (int i = 0; i < numCourses; i++) { 48 map.put(i, new HashSet<Integer>()); 49 } 50 for (int i = 0; i < prerequisites.length; i++) { 51 map.get(prerequisites[i][1]).add(prerequisites[i][0]); 52 } 53 return map; 54 } 55 }
9. Minimum Spanning Tree
Given a list of Connections, which is the Connection class (the city name at both ends of the edge and a cost between them), find some edges, connect all the cities and spend the least amount. Return the connects if can connect all the cities, otherwise return empty list. Return the connections sorted by the cost, or sorted city1 name if their cost is same, or sorted city2 if their city1 name is also same. Example Gievn the connections = ["Acity","Bcity",1], ["Acity","Ccity",2], ["Bcity","Ccity",3] Return ["Acity","Bcity",1], ["Acity","Ccity",2]
思路:核心是先按要求对Connection排序,用Map记录每个节点的父节点,依次从小到大取出Connection,当新边的所连接的两个城市的院root相同时,不加入(加入就构成了环);不同则加入,同时合并两个root,以确保连通性。
1 /** 2 * Definition for a Connection. 3 * public class Connection { 4 * public String city1, city2; 5 * public int cost; 6 * public Connection(String city1, String city2, int cost) { 7 * this.city1 = city1; 8 * this.city2 = city2; 9 * this.cost = cost; 10 * } 11 * } 12 */ 13 public class Solution { 14 /** 15 * @param connections given a list of connections include two cities and cost 16 * @return a list of connections from results 17 */ 18 public List<Connection> lowestCost(List<Connection> connections) { 19 // Write your code here 20 List<Connection> result = new ArrayList<>(); 21 if (connections == null || connections.size() == 0) { 22 return result; 23 } 24 Comparator<Connection> cmp = new Comparator<Connection>() { 25 public int compare(Connection a, Connection b) { 26 if (a.cost != b.cost) { 27 return a.cost - b.cost; 28 } 29 if (!a.city1.equals(b.city1)) { 30 return a.city1.compareTo(b.city1); 31 } 32 return a.city2.compareTo(b.city2); 33 } 34 }; 35 Collections.sort(connections, cmp); 36 Map<String, String> map = new HashMap<>(); 37 for (Connection connection : connections) { 38 String city1 = connection.city1; 39 String city2 = connection.city2; 40 map.put(city1, city1); 41 map.put(city2, city2); 42 } 43 int size = map.size(); 44 for (Connection connection : connections) { 45 String city1 = connection.city1; 46 String city2 = connection.city2; 47 if (union(city1, city2, map)) { 48 result.add(connection); 49 } 50 } 51 if (result.size() != size - 1) { 52 return new ArrayList<Connection>(); 53 } 54 return result; 55 } 56 public boolean union(String a, String b, Map<String, String> map) { 57 String aRoot = findRoot(a, map); 58 String bRoot = findRoot(b, map); 59 if (aRoot.equals(bRoot)) { 60 return false; 61 } 62 map.put(bRoot, aRoot); 63 return true; 64 } 65 public String findRoot(String a, Map<String, String> map) { 66 if (map.get(a).equals(a)) { 67 return a; 68 } 69 return findRoot(map.get(a), map); 70 } 71 }