代码改变世界

LeetCode算法编程之连载四(二分法)

2014-11-09 15:38  commandow  阅读(630)  评论(0编辑  收藏  举报

1、题目 – Sqrt(x)

Implement int sqrt(int x).

Compute and return the square root of x.

题目意思很简单,就是求出x的平方根。

分析:

一看这题目,感觉很简单,很容易想到的是二分法,我最开始的解法是从1、2、4、8 … 2 * n,计算出n < x < 2n,然后再在 n 和 2n间,用二分法,找到平方根结果。

这种方法比较麻烦的一点是,乘积是有可能越界的,要处理乘积越界的情况,代码可读性不强。

class Solution {
public:
    int sqrt(int x) {
        int base = 1;
        int product = base * base;

        while (product < 0
               || (product > 0 && product < x))
        {
            base *= 2;
            product = base * base;
        }

        if (product == x)
        {
            return base;
        }

        int start = base / 2;
        int end = base;

        int med = start + (end - start) / 2;

        while (start != med)
        {
            int product = med * med;
            if ((product >= 0 && product > x) || product < 0)
            {
                end = med;
            }
            else
            {
                start = med;
            }

            med = start + (end - start) / 2;
        }

        return med;
    }
};

要解决乘积越界的情况,有没有什么好的办法呢?能不能思考一下,在32位可表达的情况下,平方根可能出现的最大的情况?想到位图是不是可以来表示呢?利用二分法

(1 << 16)的平方为1 << 32位(这已越界),那么最大值是1 << 15,既然知道可表示的最大位数是15,那么依次往低走,根据乘积与x的比较看看每一位可否置1,根据这个思路,有了位图的解决方法:

class Solution {
public:
    int sqrt(int x) {

        unsigned int res = 0;
        int bit = 1 << 15;

        while (bit > 0)
        {
            res |= bit;
            if (res * res > x)
            {
                res ^= bit;
            }

            bit >>= 1;
        }

        return res;
    }
};

这个代码是不是很漂亮了

2、题目 - Search a 2D Matrix

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

    Integers in each row are sorted from left to right.
    The first integer of each row is greater than the last integer of the previous row.

For example,

Consider the following matrix:

[
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]

题目解释:

输入为一个m x n的矩阵,矩阵每行已从小到大排序,每行第一个数大上一行的最后一个数,在矩阵中是否能找到数x。

分析:

很容易想到,先到这个数所在行,然后在找到这个数所在的列。当然依次遍历过去的是可以的,反正是已经排过序的,这是最笨的方法。但作为搞算法的,最基本的方法就是二分法,

思路是一样的,利用行二分法,找到所在行,再利用列二分法,找到所在的列。

class Solution {
public:
    bool searchMatrix(vector<vector<int> > &matrix, int target) {

        int row = matrix.size();
        if (row == 0)
        {
            return false;
        }

        int col = matrix[0].size();

        int start = 0;
        int end = row - 1;
        int med = start + (end - start) / 2;

        // 二分法找行
         while (med != start)
        {
            if (matrix[med][0] == target)
            {
                return true;
            }

            if (matrix[med][0] > target)
            {
                end = med;
            }
            else
            {
                start = med;
            }

            med = start + (end - start) / 2;
        }

        int exact_row = end;
        if (matrix[end][0] > target)
        {
            exact_row = start;
        }

        start = 0;
        end = col - 1;
        med = start + (end - start) / 2;

        // 二分法找列
         while (start != med)
        {
            if (matrix[exact_row][med] == target)
            {
                return true;
            }

            if (matrix[exact_row][med] > target)
            {
                end = med;
            }
            else
            {
                start = med;
            }

            med = start + (end - start) / 2;
        }

        if (matrix[exact_row][start] == target
            || matrix[exact_row][end] == target)
        {
            return true;
        }

        return false;
    }
};