• 算法题解之二分法


    Count Complete Tree Nodes          

    完全二叉树的节点数

    思路:这道题使用暴力法为O(n)会超时。使用二分的思想,首先求出左右子树的深度,如果它们的深度相同,则说明左子树为满树,它的节点数可由公式2^h-1求得;如果不相同,说明右子树为满树,同样可用公式求得它的节点数。然后再递归的去求另一个子树。时间复杂度为O(lgn * lgn)。

    这道题的一个优化方法是:每次递归函数都要求2^h,如果调用Math.pow(2, h)会很慢,因此用1<<h来求2^h就能AC了。

    public class Solution {
        public int countNodes(TreeNode root) {
            if (root == null) {
                return 0;
            }
            int left_h = 0;
            int right_h = 0;
            TreeNode cur = root.left;
            while (cur != null) {
                cur = cur.left;
                left_h++;
            }
            cur = root.right;
            while (cur != null) {
                cur = cur.left;
                right_h++;
            }
            
            if (left_h != right_h) {
                return (1 << right_h) + countNodes(root.left);
            } else {
                return (1 << left_h) + countNodes(root.right);
            }
            
        }
    }
    View Code

     

    Divide Two Integers

    两个整数相除

    思路:将除数不断乘2(左移1位),直到大于被除数,此时的余数作为被除数继续除以除数,直到满足除数大于余数。排除-2147483649/-1和除数为0这两种溢出情况,其余均转化为long类型来做。

    public class Solution {
        public int divide(int dividend, int divisor) {
            if (divisor==0 || (dividend == Integer.MIN_VALUE && divisor == -1)) {
                return Integer.MAX_VALUE;
            }
            long result = 0;
            long dd = Math.abs((long)dividend);
            long dr = Math.abs((long)divisor);
                
            while (dd >= dr) {
                long tmp = dr;
                long re = 1;
                while (dd >= tmp) {
                    tmp <<= 1;
                    re <<= 1;
                }
                tmp = tmp >> 1;
                re = re >> 1;
                dd = dd - tmp;
                result = result + re;
            }    
            
            if ((dividend > 0 && divisor<0) || (dividend < 0 && divisor > 0))
                return (int)(-result);
            
            return (int)result;
        }
    }
    View Code

     

    Factorial Trailing Zeroes

    阶乘结果末尾0的个数

    思路:末尾的0只可能由2*5产生,考虑乘式可以分解为a个2和b个5相乘,a和b的最小值就是末尾0的个数。

       2的个数 = 所有因子中能被2整除的个数 + 所有因子中能被4整除的个数 + 所有因子中能被8整除的个数······

       5的个数 = 所有因子中能被5整除的个数 + 所有因子中能被25整除的个数 + 所有因子中能被125整除的个数······

     1 public class Solution {
     2     public int trailingZeroes(int n) {
     3         long twobase = 2;
     4         long fivebase = 5;
     5         long twoNum = 0;
     6         long fiveNum = 0;
     7         while (twobase <= n) {
     8             twoNum += n / twobase;
     9             twobase *= 2;
    10         }
    11         while (fivebase <= n) {
    12             fiveNum += n / fivebase;
    13             fivebase *= 5;
    14         }
    15         
    16         return (int)Math.min(twoNum, fiveNum);
    17     }
    18 }
    View Code

    H-Index II

    H指数II

    思路:本题是H-indexI的follow up。如I中分析,当数组是升序时,要找到第一个满足citations[i] >= N - i的元素,想到用二分search。

     1 public class Solution {
     2     public int hIndex(int[] citations) {
     3         if (citations == null || citations.length == 0) {
     4             return 0;
     5         }
     6         int N = citations.length;
     7         int start = 0;
     8         int end = N - 1;
     9         while (start + 1 < end) {
    10             int mid = (start + end) / 2;
    11             if (citations[mid] >= N - mid) {
    12                 end = mid;
    13             } else {
    14                 start = mid;
    15             }
    16         }
    17         if (citations[start] >= N - start) {
    18             return N - start;
    19         }
    20         if (citations[end] >= N - end) {
    21             return N - end;
    22         }
    23         return 0;
    24     }
    25 }
    View Code

    Kth Smallest Element in a Sorted Matrix

    找二维排序数组中第k小的元素

    思路1:用堆。先把第一行加到堆中,然后每弹出一个元素,就把它下面那个元素加到堆中。时间复杂度是O(klgn)。

     1 public class Solution {
     2     public int kthSmallest(int[][] matrix, int k) {
     3 
     4         int n = matrix.length;
     5         PriorityQueue<Element> q = new PriorityQueue<Element>();
     6         for (int i = 0; i < n; i++) {
     7             q.offer(new Element(0, i, matrix[0][i]));
     8         }
     9         for (int i = 1; i < k; i++) {
    10             Element cur = q.poll();
    11             if (cur.x < n - 1) {
    12                 q.offer(new Element(cur.x + 1, cur.y, matrix[cur.x + 1][cur.y]));
    13             }
    14         }
    15         
    16         return q.poll().val;
    17     }
    18 }
    19 
    20 class Element implements Comparable<Element> {
    21     int x, y, val;
    22     Element(int x, int y, int val) {
    23         this.x = x;
    24         this.y = y;
    25         this.val = val;
    26     }
    27     public int compareTo(Element e) {
    28         return val - e.val;
    29     }
    30 }
    View Code

    思路2:二分法。要查找的范围是m~n,m是矩阵左上角的数,n是矩阵右下角的数。对于m和n的中间数mid,计算矩阵中小于mid的数的个数是count。如果count < k,则mid左边的数一定不会是要找的第K个数(这里可以用反证法),因此丢弃mid左边;如果count >= k,同样丢弃mid的右边。最后剩下两个数。

    这里计算矩阵中小于num的数的个数使用的方法lowerCountInMatrix(),与seach a 2D matrixII一样,即从右上角开始。

    时间复杂度是O(nlgX),X是矩阵中最大数与最小数的差值。

     1 public class Solution {
     2     public int kthSmallest(int[][] matrix, int k) {
     3         int start = matrix[0][0];
     4         int end = matrix[matrix.length - 1][matrix.length - 1];
     5         while (start + 1 < end) {
     6             int mid = (end - start) / 2 + start;
     7             int count = lowerCountInMatrix(mid, matrix);
     8             if (count < k) {
     9                 start = mid;
    10             } else {
    11                 end = mid;
    12             }
    13         }
    14         
    15         int start_count = lowerCountInMatrix(start, matrix);
    16         int end_count = lowerCountInMatrix(end, matrix);
    17         
    18         if (end_count >= k) {
    19             return start;
    20         }
    21         return end;
    22     }
    23     
    24     public int lowerCountInMatrix(int num, int[][] matrix) {
    25         int count = 0;
    26         int i = 0, j = matrix.length - 1;
    27             
    28         while (i < matrix.length && j >= 0) {
    29             if (matrix[i][j] < num) {
    30                 count += j + 1;
    31                 i++;
    32             } else {
    33                 j--;
    34             }
    35         }
    36         return count;
    37     }
    38 }
    View Code

    Search a 2D Matrix II

    搜索2维矩阵II

    思路:本题思想跟二分法类似(但不是二分),即每次根据判断丢弃掉一些范围,将搜索范围缩小。方法是:选取右上角的数作为起点,如果大于target,则丢弃它所在的列;如果小于target,则丢弃掉它所在的行;如果等于target,则计数加1并同时丢弃所在行和列。当右上角超出矩阵范围时结束算法。

    public class Solution {
        /**
         * @param matrix: A list of lists of integers
         * @param: A number you want to search in the matrix
         * @return: An integer indicate the occurrence of target in the given matrix
         */
        public int searchMatrix(int[][] matrix, int target) {
            // write your code here
            if (matrix == null || matrix.length == 0) {
                return 0;
            }
            if (matrix[0] == null || matrix[0].length == 0) {
                return 0;
            }
            int m = matrix.length;
            int n = matrix[0].length;
            int i = 0;
            int j = n - 1;
            int count = 0;
            while (i < m && j >= 0) {
                if (matrix[i][j] > target) {
                    j--;
                } else if (matrix[i][j] < target) {
                    i++;
                } else {
                    count++;
                    i++;
                    j--;
                }
            }
            return count;
        }
    }
    View Code
  • 相关阅读:
    digits
    Graph
    noip2013货车运输
    noip2013华容道
    codevs科技庄园
    POJ3321 Apple tree
    第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛--F-等式
    第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛--E-回旋星空
    第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛--D-psd面试
    第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛--A-跳台阶
  • 原文地址:https://www.cnblogs.com/coldyan/p/6017551.html
Copyright © 2020-2023  润新知