這是所有類型里我覺得最有趣的一個類型,哈哈。
來被虐一下。
258. Add Digits
數(shù)字根的性質(zhì):
- 任何數(shù)字加9的數(shù)字根都是本身:加9的過程,就是在個位數(shù)-1,十位數(shù)+1的過程,所以加上9以后,個位數(shù)和十位數(shù)的數(shù)字和不變
- 任何數(shù)字乘9的數(shù)字根都是9:任何數(shù)字乘以9,就是9一直加很多很多次,利用第一個性質(zhì),還是會回到9
- 計算一般數(shù)字的數(shù)字根:前兩個性質(zhì)都跟9密切相關(guān),那么對于一般數(shù)字,我們也盡量跟9扯上關(guān)系。比如12=9+3,那么利用第一個性質(zhì),數(shù)字根就是3。123 = 13*9 + 6,利用前兩個性質(zhì),數(shù)字根是6。對于數(shù)字N,N - floor(N / 9) * 9是它的數(shù)字根。而對于數(shù)字9,9 = 1 * 9 + 0,余數(shù)是0時,數(shù)字根為9。另外還有一種情況,0 = 0 * 9 + 0,余數(shù)是0時,數(shù)字根也可能是9。為了區(qū)分這兩種情況,可以將公式改成N - floor((N - 1) / 9) * 9,由于floor函數(shù)的性質(zhì)
- 另外一個我沒想出原理的性質(zhì):計算一個大數(shù)的數(shù)字根,可以把那個數(shù)字中相加為9的數(shù)字先劃掉。比如123456789,數(shù)字根是0,因為9,18,27,36,45,都可以被劃掉——why?
168. Excel Sheet Column Title
Given a positive integer, return its corresponding column title as appear in an Excel sheet.
For example:
1 -> A
2 -> B
3 -> C
...
26 -> Z
27 -> AA
28 -> AB
從數(shù)字10進制比擬到26進制。
class Solution {
public:
string convertToTitle(int n)
{
string res;
while (n)
{
// 將數(shù)字轉(zhuǎn)換為char的方法和26進制的對應(yīng)關(guān)系,避免最后翻轉(zhuǎn)字符串
res = char('A' + (n - 1) % 26) + res;
// 就像我們從尾到頭遍歷一個十進制的數(shù)的時候,用/10來得出下一位是什么
// 但在這里,要注意對應(yīng)關(guān)系
n = (n - 1) / 26;
}
return res;
}
};
171. Excel Sheet Column Number
接上題,從字符串轉(zhuǎn)換成數(shù)字。
我的做法,從后往前遍歷:
class Solution {
public:
int titleToNumber(string s)
{
// ADS=S:19*1
// AD=D:4*26
// A=1*26*26
int n = 0, p = 0;
while (s.size())
{
int add = (s.back() - 'A' + 1);
n += add * pow(26, p++);
s.pop_back();
}
return n;
}
};
看了答案,從前往后遍歷,但本質(zhì)是一樣的:
class Solution {
public:
// ADS
// A:ans=0+1=1
// D:ans=1*26+4=30
// S:ans=30*26+19=(1*26+4)*26+19
int titleToNumber(string s) {
int base = 26;
int ans = 0;
for(int i = 0; i < s.size(); i++) {
ans = ans* base + (s[i] - 'A' + 1);
}
return ans;
}
};
我一開始覺得有點不可思議,從前往后的怎么知道第一個數(shù)字要乘幾遍26呢?比如第一個數(shù)我乘了26,下一個數(shù)要乘26的時候,已經(jīng)加上第一個數(shù)了,會起到什么影響呢?其實這就是起到了正確的影響,每次加現(xiàn)在的數(shù)之前把前面的數(shù)*26,最后每個數(shù)都會乘了正確的次數(shù)。
我們做10進制時其實也是這樣。比如1234。第一次ans=1,第二次ans=110+2=12,第三次ans=1210+3=123,第四次12310+4。最后這個1234=(((1)10+2)10 + 3)10 + 4。
172. Factorial Trailing Zeroes
Given an integer n, return the number of trailing zeroes in n!.
我們知道,只有2*5的組合能產(chǎn)生0。所以我們要想辦法找到一個數(shù)是由幾個2,幾個5組成。而由于我們需要2和5來產(chǎn)生0,而2是每兩個數(shù)字產(chǎn)生一個,5是每五個數(shù)字產(chǎn)生一個,5的頻率比2小得多,所以我們要找的其實是5出現(xiàn)的頻率。
舉例:n=5,10,15,20 => 5出現(xiàn)的次數(shù)=N/5。而25中5出現(xiàn)的次數(shù)為6,因為25=5*5。相應(yīng)地,像50,75,100,125都有這種情況。所以我們可以通過/5, /25, /125...來尋找5出現(xiàn)的次數(shù)。/25的結(jié)果中不包括/5的結(jié)果,因此我們直接將結(jié)果相加就好了。終止條件在于,n/i要大于0。
int trailingZeroes(int n) {
int result = 0;
for(long long i=5; n/i>0; i*=5){
result += (n/i);
}
return result;
}
觀察以上代碼,i*=5,其實就相當(dāng)于n/=5,所以也可以轉(zhuǎn)化寫成遞歸式子:
class Solution {
public:
int trailingZeroes(int n)
{
return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5);
}
};
202. Happy Number
Write an algorithm to determine if a number is "happy".
A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.
這道題的解法很簡單,用map(如果一個數(shù)[即兩個之前數(shù)的平方和]出現(xiàn)了兩次的話,肯定是進入循環(huán)模式了)或者fast/slow pointer.
7. Reverse Integer
Reverse digits of an integer.
Example1: x = 123, return 321
Example2: x = -123, return -321
這道題第一反應(yīng)是轉(zhuǎn)化為string來做,但是仔細(xì)一想,應(yīng)該考慮幾個edge case:
1、leading/trailing zero的情況
2、interger overflow的情況
319. Bulb Switcher
There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every second bulb. On the third round, you toggle every third bulb (turning on if it's off or turning off if it's on). For the ith round, you toggle every i bulb. For the nth round, you only toggle the last bulb. Find how many bulbs are on after n rounds.
這道題要求的是一個數(shù)有幾個因子,更準(zhǔn)確地說,是一個數(shù)的因子的奇偶性。如果是偶數(shù)個那燈就是關(guān)的,如果是奇數(shù)個那燈就是亮的。除了因式分解之外,還有什么辦法來知道因子的奇偶性呢?
一個insight:因子成對出現(xiàn)。只有平方數(shù)的因子是奇數(shù)。所以如果現(xiàn)在有N盞燈,那么第N盞燈假如是個平方數(shù),那么sqrt(N)代表了[1,N]之中有多少個平方數(shù),也就是有多少個數(shù)的因子數(shù)是奇數(shù),也就是這個問題的答案。如果N不是平方數(shù),那么floor(sqrt(N))就是答案。所以代碼為:
class Solution {
public:
int bulbSwitch(int n)
{
return sqrt(n);
}
};
223. Rectangle Area
Find the total area covered by two rectilinear rectangles in a 2D plane.
這道要求兩個長方形的和減去重合部分的面積。因為ABCD和EFGH的相對位置太不確定了,任何情況都要討論兩遍,所以我先把A確定為四條豎邊中最左邊的邊,算出寬,然后把C確定為四條橫邊中最上面的邊,算出高。這樣減少了很多討論情況,但是速度有點慢,主要是花在swap上了。
class Solution {
public:
int computeArea(int A, int B, int C, int D, int E, int F, int G, int H)
{
int two_rec_sum = (C - A) * (D - B) + (G - E) * (H - F);
int h, w;
if (E >= C || G <= A || H <= B || F >= D) return two_rec_sum;
if (E < A) swap(A, E), swap(B, F), swap(C, G), swap(D, H);
w = G <= C ? G - E : C - E;
if (D < H) swap(A, E), swap(B, F), swap(C, G), swap(D, H);
h = F <= B ? H - B : H - F;
return two_rec_sum - w * h;
}
};
其實還可以減少討論情況。一個insight是,重合長方形的左邊是兩個左邊橫坐標(biāo)較大的那個,右邊是兩個右邊橫坐標(biāo)較小的那個,上邊是兩個上邊縱坐標(biāo)較小的那個,下邊是兩個下邊縱坐標(biāo)較大的那個。另外,檢查一下是否有沒重合的情況。
class Solution {
public:
int computeArea(int A, int B, int C, int D, int E, int F, int G, int H)
{
int two_rec_sum = (C - A) * (D - B) + (G - E) * (H - F);
int left = max(A, E);
int right = min(C, G);
int top = min(D, H);
int bottom = max(B, F);
if (left <= right && top >= bottom)
{ return two_rec_sum - (right - left) * (top - bottom); }
return two_rec_sum;
}
};
這種題的類型或者說思維挺常見的——有很多種情況要討論,怎樣去抽象出同樣的情況,避免討論的情形,最后用簡單的思路去寫出代碼。之前遇到過的情況是,兩種我以為應(yīng)該分開討論的情況其實有先后順序,還有就是類似這道題的,看似很多種情況,但是其實可以簡化啦。
166. Fraction to Recurring Decimal
Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.
If the fractional part is repeating, enclose the repeating part in parentheses.
For example,
Given numerator = 1, denominator = 2, return "0.5".
Given numerator = 2, denominator = 1, return "2".
Given numerator = 2, denominator = 3, return "0.(6)".
這種題我覺得是math里最適合編程的一種題,就是對公理定理的要求不多,主要考你發(fā)現(xiàn)規(guī)律的能力,以及更重要的,在編程中把握細(xì)節(jié)、思考edge case的能力。這道題的總體思路很簡單,不停將余數(shù)*10,除以被除數(shù),用map檢查有無重復(fù)出現(xiàn)的情況。但是這里有很多的edge case需要考慮:
- 正負(fù)——如果不提前處理好符號的問題,答案中會出現(xiàn)像“6.-2-3”這樣的情況。可以用亦或(^)的邏輯來判定
- 零——用亦或的邏輯判斷出來的結(jié)果只有正負(fù)之分,還要考慮0的情況
- 整數(shù)溢出。一旦遇到integer,就要考慮一下這道題會不會有整數(shù)溢出的情況。這道題有很多的整數(shù)溢出,比如INT_MIN/-1,1/INT_MIN等等,所以我們要將所有數(shù)字都轉(zhuǎn)換為64位整數(shù)來做(long long or int64_t)
class Solution {
public:
string fractionToDecimal(int numerator, int denominator)
{
// edge case
if (!numerator) return "0";
// in case integer overflow
long long n = (long long)numerator;
long long d = (long long)denominator;
unordered_map<int, int> map;
string res;
// decide the sign
if (n < 0 ^ d < 0) res += '-';
// convert the sign
n = abs(n), d = abs(d);
long long q = n / d;
res += to_string(q);
long long r = n - q * d;
if (!r) return res;
res += '.';
while (r)
{
if (map.find(r) != map.end())
{
res.insert(map[r], "(");
res.push_back(')');
break;
}
map[r] = res.size();
r *= 10;
q = r / d;
res += to_string(q);
r = r - d * q;
}
return res;
}
};
368. Largest Divisible Subset
Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = 0 or Sj % Si = 0.
If there are multiple solutions, return any subset is fine.
這道題我用DFS做,思路和答案都很明顯,但是比較慢,占用空間也大,因為每個index都存了一個vector。這個其實可以用dp的思想方法做,并用一個parent vector來backtrace。dp的思想方法,經(jīng)常用到的有背包問題、狀態(tài)轉(zhuǎn)換、定義子問題、定義遞歸關(guān)系式等思路。DP的遞歸式可推出:dp[i] = dp[j] + 1 if i % j == 0, else dp[i] = 1. 也就是說以dp[i]結(jié)尾的集合中元素的個數(shù),要么是能被之前元素除斷的,要么只有dp[i]本身。寫碼的時候,空集、只有一個元素的集合、dp數(shù)組的初始值等條件要考慮過。
453. Minimum Moves to Equal Array Elements
Given a non-empty integer array of size n, find the minimum number of moves required to make all array elements equal, where a move is incrementing n - 1 elements by 1.
這道題有兩個方法:令一開始的和為sum,最小值是min,操作次數(shù)為k次。
- 逆向思維——每次n-1個元素都+1,就是每次1個元素-1。看減幾次能每個元素都變成最小數(shù)。
- 順向思維——最小值min在每一輪的操作中都應(yīng)該+1,而在操作之后它還是會是最小的值。因為min和其它幾個比它大的數(shù)一起+1,其它幾個比它大但又不是最大數(shù)的數(shù)([S])+1之后一定比min+1大,而原來的最大數(shù)max雖然沒有變,但也比min大,因為max>=all([S]+1)。([S]中的數(shù)各加一)所以這個最小值從開始到結(jié)束都是最小值,我們知道最后我們達(dá)到的值是min+k。可以列出等式:sum + (n - 1) * k = (min + k) * n,所以k=sum-min*n。
264. Ugly Number II
Write a program to find the n-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.
Note that 1 is typically treated as an ugly number, and n does not exceed 1690.
這道題的關(guān)鍵是在O(1)的時間內(nèi)找到下一個ugly number是什么。建立一個vector來保存現(xiàn)在已經(jīng)有的ugly number。下一個ugly number的情況要么是這個number * 2,要么 * 3,要么 * 5,取其中的最小值——這由定義而來。同時每次進行指標(biāo)的更新,注意乘積相同時一起更新指標(biāo)。
class Solution {
public:
int nthUglyNumber(int n)
{
vector<int> nums {1};
int two = 0, three = 0, five = 0;
while (nums.size() != n)
{
nums.push_back(min(nums[two] * 2, min(nums[three] * 3, nums[five] * 5)));
if (nums.back() == nums[two] * 2) two++;
if (nums.back() == nums[three] * 3) three++;
if (nums.back() == nums[five] * 5) five++;
}
return nums.back();
}
};
247. Strobogrammatic Number II
A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside down).
Find all strobogrammatic numbers that are of length = n.
For example,
Given n = 2, return ["11","69","88","96"].
這道題的思路很簡單,但是我覺得我第一次寫的代碼充分暴露了丑陋。。。第一次代碼:
class Solution {
public:
vector<string> findStrobogrammatic(int n)
{
vector<string> res;
vector<string> next({"0", "1", "8"});
vector<string> basic({"11", "69", "96", "88", "00"});
vector<string> next_next = basic;
if (n == 1) return next;
for (int i = 3; i <= n; ++i)
{
vector<string> v;
for (int j = 0; j < basic.size(); ++j)
{
for (int k = 0; k < next.size(); ++k)
{
string ele = basic[j];
v.push_back(ele.insert(1, next[k]));
}
}
next = next_next;
next_next = v;
}
for (string num: next_next)
{
if (num[0] == '0' && num.size() != 1) continue;
res.push_back(num);
}
return res;
}
};
改進后的代碼:
class Solution {
public:
vector<string> findStrobogrammatic(int n)
{
vector<string> next({""});
vector<string> next_next({"0", "1", "8"});
if (n == 0) return next;
if (n == 1) return next_next;
for (int i = 2; i <= n; ++i)
{
vector<string> v;
for (string s: next)
{
if (i < n) v.push_back("0" + s + "0");
v.push_back("1" + s + "1");
v.push_back("6" + s + "9");
v.push_back("8" + s + "8");
v.push_back("9" + s + "6");
}
next = next_next;
next_next = v;
}
return next_next;
}
};
改進的地方在于:
- (最大的)處理case 0的方式。除了最后一次,“00”,“010”這樣的形式也允許存在,這是遞歸的條件的一部分。之前我是完成后還要遍歷一次去尋找是否有非法0的存在,但改進后以i==n為終止條件。這也減少了一個向量的空間
- 第一次我是以某個array為基礎(chǔ),對每一個element進行insert。這樣的一個壞處在于,因為我們不能改變basic向量,同時又要進行insert,所以每次都要復(fù)制里面的元素,再進行操作,這樣一來這個向量不知道被復(fù)制了多少遍了。改進后的代碼里,用+的形式來進行操作,更明了,code更干凈。當(dāng)情況數(shù)量有限的時候,可以采取這樣的寫法
時間復(fù)雜度上,每次n+1,遍歷的元素數(shù)量都是原來的5倍。所以我覺得時間復(fù)雜度是O(n)。
367. Valid Perfect Square
這道題應(yīng)該是讓我們養(yǎng)成一種想法——很多明顯的遍歷能做的題目,其實都能用二分法來做吧。另外,凡是關(guān)于integer的加減乘除,都要想想overflow的問題哦。
360. Sort Transformed Array
這道題我的思路是:
- 變量index表示離最小值/最大值最近的index
- 若a=0:b>0,index是第一個值,從第一個至最后一個排列;b<0,index是最后一個值,從第一個至最后一個排列
- 若a!=0,用二分法找出index值(-b/2a入手)
- 取決于a的符號,a>0時,找出離a最近至最遠(yuǎn)的元素,并從第一個至最后一個排列。a<0時,找出離a最近至最遠(yuǎn)的元素,并從最后一個到第一個排列
看了評論區(qū)的答案,可以簡化的思路步驟:
- 用二分法找出index的步驟可以省略,我們可以不從中點入手,而從端點入手
- 可以避免討論a=0的情況,因為我們只需將端點比較大小然后從前至后/從后至前排列就行了
class Solution {
private:
int func(int x, int a, int b, int c)
{
return a * x * x + b * x + c;
}
public:
vector<int> sortTransformedArray(vector<int>& nums, int a, int b, int c)
{
int i = 0, j = nums.size() - 1;
vector<int> res(nums.size());
int index = a >= 0 ? nums.size() - 1 : 0;
while (i <= j)
{
// we can compare func(nums[i]) and func(nums[j]) and decide which is larger
// but is this the "larger of small" or "larger of large"?
// when a >= 0, it's either monotonous or "larger of large"
// otherwise, "larger of small"
if (a >= 0)
{
res[index--] = func(nums[i], a, b, c) > func(nums[j], a, b, c) ? func(nums[i++], a, b, c) : func(nums[j--], a, b, c);
}
else
{
res[index++] = func(nums[i], a, b, c) > func(nums[j], a, b, c) ? func(nums[j--], a, b, c) : func(nums[i++], a, b, c);
}
}
return res;
}
};
469. Convex Polygon
Given a list of points that form a polygon when joined sequentially, find if this polygon is convex (Convex polygon definition).
這道完全是數(shù)學(xué)題了,判斷一個形狀是不是凸面體(任何兩點之間的連線都在此形狀內(nèi))。判斷方法是:將每兩條相鄰的邊進行cross product(二維向量的cross product:<a,b>x<c,d>=ad - bc),看所得數(shù)(z向量)是正還是負(fù)。如果全為正或全為負(fù),則是凸面體,反之不是。
356. Line Reflection
Given n points on a 2D plane, find if there is such a line parallel to y-axis that reflect the given points.
這道題主要考察對可能出現(xiàn)的case進行分析的能力,以及編程能力(如何選擇相應(yīng)的數(shù)據(jù)結(jié)構(gòu))。
要考慮的case有(前兩個比較edge):
- 縱坐標(biāo)只有一個點,這個點與自己對稱
- 兩個坐標(biāo)重合,此時只需考慮其中一個坐標(biāo)即可
- 兩個坐標(biāo)不重合且成對出現(xiàn),將同一個縱坐標(biāo)上出現(xiàn)的橫坐標(biāo)進行遞增排序,用兩個指針求出對稱軸并在循環(huán)中檢查
數(shù)據(jù)結(jié)構(gòu)中要考慮的:
- 利用set是為了實現(xiàn)【遞增】和【去重】兩個功能
- set的pointer不是random access pointer,所以我們不能像vector一樣對pointer進行大小比較,我們只能每次將pointer++或者--,并且判斷兩個pointer是否相等。這就要求我們在編程的時候?qū)K止條件要進行一點點小的靈巧的改變,見代碼
class Solution {
public:
bool isReflected(vector<pair<int, int>>& points)
{
unordered_map<int, set<int>> map;
for (auto &p: points) map[p.second].insert(p.first);
double x = (double)INT_MAX;
for (auto &item: map)
{
for (auto l = item.second.begin(), r = item.second.end(); l != r; l++)
{
// 先將r pointer--。由于先減了r,我們可以對終止條件有更靈活的判斷方式
double mid = (double)(*l + *(--r)) / 2;
if (x == (double)INT_MAX) x = mid;
else if (x != mid) return false;
// 若此時l和r相等,表示已經(jīng)進行到了同一個元素,可以退出了
if (l == r) break;
}
}
return true;
}
};
537. Complex Number Multiplication
這道題考察stringstream的用法。想在字符串中取出整數(shù),或者用整數(shù)去構(gòu)造字符串,分別可以用istringstream和ostringstream。另外用istream& getline (istream& is, string& str, char delim);
也可以取出相關(guān)信息。
class Solution {
public:
string complexNumberMultiply(string a, string b)
{
int ra, ia, rb, ib;
char buff;
stringstream aa(a), bb(b), ans;
aa >> ra >> buff >> ia >> buff;
bb >> rb >> buff >> ib >> buff;
ans << ra*rb - ia*ib << "+" << ra*ib + rb*ia << "i";
return ans.str();
}
};
523. Continuous Subarray Sum
Given a list of non-negative numbers and a target integer k, write a function to check if the array has a continuous subarray of size at least 2 that sums up to the multiple of k, that is, sums up to n*k where n is also an integer.
這道題用O(n^2)的解法考慮0的edge case就可以了。不過有一種數(shù)學(xué)的解法挺巧妙的。題目似乎給了一個不太用的上的restriction——sums up to the multiple of k。為什么不是直接sum up to k呢?而且讓我們返回的是一個boolean,而不是一個vector。實際上,
483. Smallest Good Base
For an integer n, we call k>=2 a good base of n, if all digits of n base k are 1.
Now given a string representing n, you should return the smallest good base of n in string format.
Example 1:
Input: "13"
Output: "3"
Explanation: 13 base 3 is 111.
Example 2:
Input: "4681"
Output: "8"
Explanation: 4681 base 8 is 11111.
Example 3:
Input: "1000000000000000000"
Output: "999999999999999999"
Explanation: 1000000000000000000 base 999999999999999999 is 11.
Note:
The range of n is [3, 10^18].
The string representing n is always valid and will not have leading zeros.
對于每一個大于2的數(shù),我們總能找出一個base k,因為最后一位digit1其實代表的就是數(shù)字1,只要n-1就是我們能找到的最大base,k進制表示為11。那么對于更小的base,其實肯定有更多的數(shù)位來表示。如果一個數(shù)能表示成111...11(m+1位),那么我們知道,這個base k肯定比n^(1/m)小,因為 k^m + k^(m-1) + ... + 1 = n。所以舉例來說,對于111這樣的進制形式,我們只要測試k < n^(1/3)就可以了。但這樣還是有很多情況要測定。 但是我們真的有必要測試比n^(1/m) 小的數(shù)嗎?對于111這樣的進制形式,當(dāng)我們測定k=sqrt(n)不正確的時候,由于(sqrt(n)-1)^ 2+(sqrt(n)-1)^ 1+(sqrt(n)-1)^0 < (sqrt(n))^ 2(相差n),我們知道n^ (1/3)以下的base其實都不會成立(太小了)。更general的case來說,k=n^(1/m) 不正確的時候,由于(n^(1/m) - 1)^m + (n^(1/m) - 1)^(m-1) + ... + 1 < (n^ (1/m))^m (因為n^a + n^ (a-1)+...+1<(n+1)^k ,說明當(dāng)k=n^(1/m) - 1的時候,k^m + k^(m-1) +...+1 < (k+1)^m < n),n^(1/m) 以下的base其實也不會成立。所以當(dāng)k=n^(1/m)過大的時候,我們沒有必要再檢查小于
k的數(shù)了。當(dāng)k=n^(1/m) 過小的時候,我們也沒有必要再檢查大于k的數(shù)了,因為(k+1)^m > n。所以我們只要檢查k=n^(1/m)這一種情況即可。
所以在進制上,每加一個1,我們就要檢查一次,最多檢查logn次。
517. Super Washing Machines
365. Water and Jug Problem
兩瓶水倒來倒去,能否倒到一個指定的高度(一瓶中的容量或兩瓶容量之和)。我們能準(zhǔn)確地測量出兩瓶水的容量(Aml和Bml)。這道題讓我覺得很麻煩的是,只有兩個瓶子。如果有第三個瓶子的話,我們每次會向這個瓶子里倒進/出Aml/Bml,能否最后倒成Zml的話,只要看AX+BY=Z這個方程有沒有解。根據(jù)Bézout's theorem,Z必須是A和B的最大公約數(shù)的倍數(shù)。按這樣的思路來,編程就很簡單了。但這里剩下兩個問題:
- 有無這個假設(shè)的第三個瓶子對最后的解有無影響
- 如果不知道這個定理,如何進行解答
50. Pow(x, n)
x ^ 8 = ((x ^ 2) ^ 2) ^ 2
x ^ 10 = (((x ^ 2) ^ 2) ^ 2) * (x ^ 2)
x ^ 16 = (((x ^ 2) ^ 2) ^ 2) ^ 2
x ^ 17 = x * (((x ^ 2) ^ 2) ^ 2) ^ 2
舉幾個例子可以看到,n由幾次2相乘,與n的bit個數(shù)有關(guān)。8=1000,10=1010,16=10000,17=10001。所以我們可以以bit數(shù)計數(shù),將n *= n進行(bit個數(shù))次,如果bit值為1的話,就乘到