算法OA 9题

文章目录

    • 626. Rectangle Overlap
    • 612. K个最近的点
    • 604. Window Sum
    • 627. 最长回文串
    • 105. 复制带随机指针的链表
    • 616. Course Schedule II
    • 628. Maximum Subtree

626. Rectangle Overlap

给定两个矩形,判断这两个矩形是否有重叠。

Example
样例 1:

输入 : l1 = [0, 8], r1 = [8, 0], l2 = [6, 6], r2 = [10, 0]
输出 : true
样例 2:

输入 : [0, 8], r1 = [8, 0], l2 = [9, 6], r2 = [10, 0]
输出 : false
Notice
l1代表第一个矩形的左上角
r1代表第一个矩形的右下角
l2代表第二个矩形的左上角
r2代表第二个矩形的右下角

保证:l1 != r2 并且 l2 != r2

/**
 * Definition for a point.
 * class Point {
 *     int x;
 *     int y;
 *     Point() { x = 0; y = 0; }
 *     Point(int a, int b) { x = a; y = b; }
 * }
 */
public class Solution {
     
    /**
     * @param l1: top-left coordinate of first rectangle
     * @param r1: bottom-right coordinate of first rectangle
     * @param l2: top-left coordinate of second rectangle
     * @param r2: bottom-right coordinate of second rectangle
     * @return: true if they are overlap or false
     */
    public boolean doOverlap(Point l1, Point r1, Point l2, Point r2) {
     
        // write your code here
        return !resolve(l1, r1, l2, r2);
    }
    private boolean resolve(Point l1, Point r1, Point l2, Point r2) {
     
        // 不重叠的情况
        return r2.x < l1.x || r1.x < l2.x || l2.y < r1.y || l1.y < r2.y;
    }
}

612. K个最近的点

给定一些 points 和一个 origin,从 points 中找到 k 个离 origin 最近的点。按照距离由小到大返回。如果两个点有相同距离,则按照x值来排序;若x值也相同,就再按照y值排序。

Example
例1:

输入: points = [[4,6],[4,7],[4,4],[2,5],[1,1]], origin = [0, 0], k = 3
输出: [[1,1],[2,5],[4,4]]
例2:

输入: points = [[0,0],[0,9]], origin = [3, 1], k = 1
输出: [[0,0]]

解法:这个题目使用最小堆解决,使用优先队列(PriorityQueue),关键是Comparator的写法。

/**
 * Definition for a point.
 * class Point {
 *     int x;
 *     int y;
 *     Point() { x = 0; y = 0; }
 *     Point(int a, int b) { x = a; y = b; }
 * }
 */

public class Solution {
     
    /**
     * @param points: a list of points
     * @param origin: a point
     * @param k: An integer
     * @return: the k closest points
     */
    public Point[] kClosest(Point[] points, Point origin, int k) {
     
        // write your code here
        Comparator<Point> comparator = (p1, p2) -> {
     
            int s1 = (p1.x - origin.x) * (p1.x - origin.x) + (p1.y - origin.y) * (p1.y - origin.y);
            int s2 = (p2.x - origin.x) * (p2.x - origin.x) + (p2.y - origin.y) * (p2.y - origin.y); 
            if (s1 == s2) {
     
                if (p1.x == p2.x) {
     
                    return p1.y - p2.y;
                } else {
     
                    return p1.x - p2.x;
                }
            }
            return s1 - s2;
        };
        Queue<Point> pq = new PriorityQueue<>(comparator);
        Point[] ans = new Point[k];
        for (Point p : points) {
     
            pq.offer(p);
        }
        for (int i = 0; i < k; i++) {
     
            ans[i] = pq.poll();
        }
        return ans;
    }
}

604. Window Sum

Given an array of n integers, 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
Example 1

Input:array = [1,2,7,8,5], k = 3
Output:[10,17,20]
Explanation:
1 + 2 + 7 = 10
2 + 7 + 8 = 17
7 + 8 + 5 = 20

public class Solution {
     
    /**
     * @param nums: a list of integers.
     * @param k: length of window.
     * @return: the sum of the element inside the window at each moving.
     */
    public int[] winSum(int[] nums, int k) {
     
        // write your code here
        if (nums.length == 0 || nums.length < k) {
     
            return new int[]{
     };
        }
        int[] sums = new int[nums.length + 1];
        for (int i = 0; i < nums.length; i++) {
     
            sums[i + 1] = sums[i] + nums[i];
        }
        int[] ans = new int[nums.length - k + 1];
        for (int i = 0; i < ans.length; i++) {
     
            ans[i] = sums[i + k] - sums[i];
        }
        return ans;
    }
}

627. 最长回文串

给出一个包含大小写字母的字符串。求出由这些字母构成的最长的回文串的长度是多少。

数据是大小写敏感的,也就是说,“Aa” 并不会被认为是一个回文串。

Example
样例 1:

输入 : s = “abccccdd”
输出 : 7
说明 :
一种可以构建出来的最长回文串方案是 “dccaccd”。
Notice
假设字符串的长度不会超过 1010。

public class Solution {
     
    /**
     * @param s: a string which consists of lowercase or uppercase letters
     * @return: the length of the longest palindromes that can be built
     */
    public int longestPalindrome(String s) {
     
        // write your code here
        if (s.length() == 0) {
     
            return 0;
        }
        char[] cs = s.toCharArray();
        int[] counts = new int[256];
        for (char c : cs) {
     
            counts[c]++;
        }
        int ans = 0;
        boolean hasSingleLetter = false;
        for (int i = 0; i < counts.length; i++) {
     
            if (counts[i] % 2 != 0) {
     
                hasSingleLetter = true;
                ans += counts[i] - 1;
            } else {
     
                ans += counts[i];
            }
        }
        return hasSingleLetter ? ans + 1 : ans;
    }
}

105. 复制带随机指针的链表

给出一个链表,每个节点包含一个额外增加的随机指针可以指向链表中的任何节点或空的节点。

返回一个深拷贝的链表。

Challenge
可否使用O(1)的空间
方法一,使用HashMap。

/**
 * Definition for singly-linked list with a random pointer.
 * class RandomListNode {
 *     int label;
 *     RandomListNode next, random;
 *     RandomListNode(int x) { this.label = x; }
 * };
 */
public class Solution {
     
    /**
     * @param head: The head of linked list with a random pointer.
     * @return: A new head of a deep copy of the list.
     */
    public RandomListNode copyRandomList(RandomListNode head) {
     
        // write your code here
        if (head == null) {
     
            return null;
        }
        Map<RandomListNode, RandomListNode> map1 = new HashMap<>();
        Map<RandomListNode, RandomListNode> map2 = new HashMap<>();
        RandomListNode dummy = new RandomListNode(0);
        RandomListNode p = dummy;
        while (head != null) {
     
            p.next = new RandomListNode(head.label);
            map1.put(head, p.next);
            map2.put(p.next, head);
            head = head.next;
            p = p.next;
        }
        p = dummy;
        while (p.next != null) {
     
            RandomListNode node = map2.get(p.next);
            RandomListNode node1 = map1.get(node.random);
            if (node1 != null) {
     
                p.next.random = node1;
            }
            p = p.next;
        }
        return dummy.next;
    }
}

更好的方法是,插入、连接、拆分三步法。

  • 插入:在原始链表的每个结点后插入一个值和它一样的新结点;则有oriNode.next == cloneNode这样的关系;
  • 连接随机结点:遍历插入新结点后的链表,在访问原始链表中的那些结点时,判断其是否有随机结点,有的话cloneNode.random = oriNode.random.next这里oriNode.random.next表示原始链表随机结点的下一个结点,其实就是复制链表的随机结点。
  • 拆分原始链表和复制链表:将奇数结点相连就是原始链表,将偶数结点相连就是我们想要的复制链表。返回复制链表的头结点即可。
/**
 * Definition for singly-linked list with a random pointer.
 * class RandomListNode {
 *     int label;
 *     RandomListNode next, random;
 *     RandomListNode(int x) { this.label = x; }
 * };
 */
public class Solution {
     
    /**
     * @param head: The head of linked list with a random pointer.
     * @return: A new head of a deep copy of the list.
     */
    public RandomListNode copyRandomList(RandomListNode head) {
     
        // write your code here
        if (head == null) {
     
            return null;
        }
        copyListNode(head);
        setRandomNode(head);
        return split(head);
    }
    // 1. 为每个结点的next插入一个和该结点的值一样的结点
    private void copyListNode(RandomListNode head) {
     
        while (head != null) {
     
            RandomListNode node = new RandomListNode(head.label);
            node.next = head.next;
            head.next = node;
            head = node.next;
        }
    }
    
    // 2. 设置每个复制结点的random
    private void setRandomNode(RandomListNode head) {
     
        RandomListNode cur = head;
        while (cur != null) {
     
            if (cur.random != null) {
     
                cur.next.random = cur.random.next;
            }
            cur = cur.next.next;
        }
    }
    // 3. 拆分链表
    private RandomListNode split(RandomListNode head) {
     
        RandomListNode cur = head;
        RandomListNode cloneCur = cur.next;
        while (cur != null) {
     
            RandomListNode cloneNode = cur.next;
            cur.next = cur.next.next;

            if (cloneNode.next != null) {
     
                cloneNode.next = cloneNode.next.next;
            }

            cur = cur.next;
        }
        return cloneCur;
    }
}

616. 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
Example 1:

Input: n = 2, prerequisites = [[1,0]]
Output: [0,1]
Example 2:

Input: n = 4, prerequisites = [1,0],[2,0],[3,1],[3,2]]
Output: [0,1,2,3] or [0,2,1,3]

public class Solution {
     
    /*
     * @param numCourses: a total of n courses
     * @param prerequisites: a list of prerequisite pairs
     * @return: the course order
     */
    public int[] findOrder(int numCourses, int[][] prerequisites) {
     
        // write your code here
         // write your code here
        int[] inDegree = new int[numCourses];
        List<List<Integer>> edges = new ArrayList<>();
        // 用于存储拓扑排序的结果
        int[] res = new int[numCourses];
        
        for (int i = 0; i < numCourses; i++) {
     
            edges.add(new ArrayList<>());
        }
        
        for (int[] pre : prerequisites) {
     
            // 记录所有边的入度
            inDegree[pre[0]]++;
            // 存储以此节点为起点的有向边
            edges.get(pre[1]).add(pre[0]);
        } 
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numCourses; i++) {
     
            if (inDegree[i] == 0) {
     
                queue.offer(i);
            }
        }
        int count = 0;
        while (!queue.isEmpty()) {
     
            int cur = queue.poll();
            res[count++] = cur;
            List<Integer> edge = edges.get(cur);
            for (int no : edge) {
     
                inDegree[no]--;
                if (inDegree[no] == 0) {
     
                    queue.offer(no);
                }
            }
        }
        return count == numCourses ? res : new int[]{
     };
    }
}

628. Maximum Subtree

Given a binary tree, find the subtree with maximum sum. Return the root of the subtree.

Example
Example 1:

Input : {1,-5,2,0,3,-4,-5}
Output : {3}
Notice
LintCode will print the subtree which root is your return node.
It’s guaranteed that there is only one subtree with maximum sum and the given binary tree is not an empty tree.

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {
     
    private TreeNode ans = null;
    private Integer maxSum = Integer.MIN_VALUE;
    /**
     * @param root: the root of binary tree
     * @return: the maximum weight node
     */
    public TreeNode findSubtree(TreeNode root) {
     
        // write your code here
        if (root == null) {
     
            return null;
        }
        solve(root);
        return ans;
    }
    
    private int solve(TreeNode root) {
     
        if (root == null) {
     
            return 0;
        }
        int curSum = solve(root.left) + solve(root.right) + root.val;
        if (ans == null || curSum > maxSum) {
     
            maxSum = curSum;
            ans = root;
        }
        return curSum;
    }
}

你可能感兴趣的:(数据结构与算法,算法,OA,9题)