1. 程式人生 > >[日常刷題]leetcode D29

[日常刷題]leetcode D29

367. Valid Perfect Square

Given a positive integer num, write a function which returns True if num is a perfect square else False.

Note: Do not use any built-in library function such as sqrt.

Example 1:

Input: 16
Output: true

Example 2:

Input: 14
Output: false

Solution in C++:

關鍵點:

  • 哈嘍

思路:

  • 開始想著之前好像也有手寫過sqrt的實現方法。然後記憶裡面就有n/2這麼個數存在,但是我舉了幾個例子,發現對於是平方的數這個適用但是對於不是的就不是很適用,但是發現加完1之後就都適用了,所以就產生了以下的方法。

方法一:暴力法

bool isPerfectSquare(int num) {
        if (num < 0)
            return false;
        for(int i = 1; i <= floor(num/2) + 1; ++i)
        {
            if ( i*i == num)
                return true;
        }
        
        return false;
    }

方法二:平方根倒數速演算法

float InvSqrt (float x)
{ float half = 0.5 * x; int i = *((int *)&x); i = 0x5f3759df - (i >> 1); x = *((float *)&i); x = x * (1.5 - (half * x * x)); return x; }

371. Sum of Two Integers

Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.

Example 1:

Input: a = 1, b = 2
Output: 3

Example 2:

Input: a = -2, b = 3
Output: 1

Solution in C++:

關鍵點:

  • 計算機計算本質

思路:

  • 一開始確實讓我有點為難,畢竟人類的思維一直都是四則運演算法則。但是當我想到數字在計算機中是二進位制表示的時候,就發現直接用位運算進行代替即可。這裡的思路是,當將a & b時得到的是未加上進位的結果,所以還需要不斷的加進位的結果,得到進位通過a ^ b即可,但是需要加到a & b的結果中還需要將進位再左移1位。如此反覆直到無進位為止即為所求。
int getSum(int a, int b) {
        // 進位
        int carry = (a & b) << 1;
        int result = a ^ b;
        while(carry){
            int tmp = result;
            result = result ^ carry;
            carry = (tmp & carry) << 1;
        }
        
        return result;
    }

374. Guess Number Higher or Lower

We are playing the Guess Game. The game is as follows:

I pick a number from 1 to n. You have to guess which number I picked.

Every time you guess wrong, I’ll tell you whether the number is higher or lower.

You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or 0):

-1 : My number is lower
 1 : My number is higher
 0 : Congrats! You got it!

Example :

Input: n = 10, pick = 6
Output: 6

Solution in C++:

關鍵點:

  • 函式返回值的含義(不要弄反了)

思路:

  • 感覺看到題目就是很明顯的二分查詢。
  • 再看解析部分,有三分的查詢的方法,比二分加快了一些。

方法一:二分查詢

// Forward declaration of guess API.
// @param num, your guess
// @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
int guess(int num);

class Solution {
public:
    
    int guessNumber(int n) {
        int left = 1;
        int right = n;
        while(left < right){
            int mid = left + (right - left) / 2;
            int result = guess(mid) ;
            if (result == 0)
                return mid;
            else if (result == 1) // 猜小了
            {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        
        return left;
    }
    
};

方法二:三分查詢

int guessNumber(int n) {
        int low = 1;
        int high = n;
        while(low < high){
            int mid1 = low + (high - low) / 3;
            int mid2 = high - (high - low) / 3;
            int res1 = guess(mid1);
            int res2 = guess(mid2);
            if (res1 == 0)
                return mid1;
            else if (res2 == 0)
                return mid2;
            else if (res1 < 0)      // pick比mid1還小
                high = mid1 - 1;
            else if (res2 > 0)      // pick比mid2還大
                low = mid2 + 1;
            else{                   // pick位於mid1與mid2之間
                low = mid1 + 1;
                high = mid2 - 1;
            }
        }
        return low;
    }

383. Ransom Note

Given an arbitrary ransom note string and another string containing letters from all the magazines, write a function that will return true if the ransom note can be constructed from the magazines ; otherwise, it will return false.

Each letter in the magazine string can only be used once in your ransom note.

Note:
You may assume that both strings contain only lowercase letters.

canConstruct("a", "b") -> false
canConstruct("aa", "ab") -> false
canConstruct("aa", "aab") -> true

Solution in C++:

關鍵點:

  • 字母

思路:

  • 開始還沒太讀懂題意,就測試了幾個輸入樣例。ab ba返回為true,再加上給的樣例,大概懂了。字母是可以重複的但是需要在另一個字串中也出現,有點像求子串但是不同的是這個子串的順序可以隨意。然後題目中只要求字母,這裡我就採用map<char,int>,第一遍掃描magazine字串獲取每個字母的次數,然後再掃描ransomNote,如果在map中沒有的字母則返回false,有的字母則數量減一,看最後是否會減到小於0
bool canConstruct(string ransomNote, string magazine) {
        
        size_t nsize = ransomNote.size();
        size_t msize = magazine.size();
        if (nsize > msize)
            return false;
        
        map<char,int> mtable;
        for(auto le : magazine){
            map<char,int>::iterator it = mtable.find(le);
            if (it != mtable.end())
                ++mtable[le];
            else
                mtable[le] = 1;
        }
        
        for(auto le : ransomNote){
            map<char,int>::iterator it = mtable.find(le);
            if (it == mtable.end())
                return false;
            else{
                --mtable[le];
                if (mtable[le] < 0)
                    return false;
            }
                
        }
        
        return true;
    }

小結

今天收穫還蠻多的,第一題的平方根倒數速演算法,雖然還有些沒有太懂,但是整體來說還是給了我一個新的思維。然後再就是第二題用計算機思維來做題。第三題的三分查詢,第四題算是鞏固了字串處理的這種思考方式。

知識點

  • 平方根倒數速演算法
  • 三分查詢、二分查詢(減法寫法)
  • 位運算求加法