29、Divide Two Integers
题目
题目要求不用乘除和取模运算,实现两个整数相除;
我的第一想法就是把除法变成减法来做,这也是最初除法的定义,其实现代码如下:
1 class Solution { 2 public: 3 int divide(int dividend, int divisor) { 4 if(1 == divisor) 5 return dividend; 6 if (-1 == divisor) 7 return 0-dividend; 8 9 bool flag = false; 10 11 if((dividend<0&&divisor>0)) 12 { 13 dividend = 0-dividend; 14 flag = true; 15 } 16 else if(dividend>0&&divisor<0) 17 { 18 divisor = 0-divisor; 19 flag = true; 20 } 21 22 dividend = abs(dividend); 23 divisor = abs(divisor); 24 25 26 int result = 0; 27 while (dividend >=divisor) 28 { 29 dividend -= divisor; 30 result++; 31 } 32 if(flag) 33 result = 0 - result; 34 35 return result; 36 37 } 38 };
看似没什么问题,但是其效率是不高的,比如被除数很大,而除数很小的时候,while循环会执行很多次,导致其效率不高,因此需要想想其他的办法解决该问题;既然直接做减法会超时,那姑且只能想移位操作了,因为移位操作是比较高效的操作,能够快速得到想要结果。如果是移位操作,应该如何下手呢?任何一个整数可以表示成以2的幂为底的一组基的线性组合,即num=a_0*2^0+a_1*2^1+a_2*2^2+...+a_n*2^n,在做除法时,dividend/divisor = num,变换一下就可以写成这样dividend = divisor*(a_0*2^0+a_1*2^1+a_2*2^2+...+a_n*2^n);因此先让divisor左移n位,然后用dividend减去这个数,剩下的结果继续用同样的方法求解n-1,代码如下:
1 class Solution { 2 public: 3 int divide(int dividend, int divisor) { 4 // Note: The Solution object is instantiated only once. 5 long long a = abs((double)dividend); 6 long long b = abs((double)divisor); 7 long long res = 0; 8 while(a >= b) 9 { 10 long long c = b; 11 for(int i = 0; a >= c; i++, c <<=1) 12 { 13 a -= c; 14 res += 1<<i; 15 } 16 } 17 18 19 if((dividend ^ divisor) >> 31) 20 res = 0-res; 21 if(res >= 2147483647) 22 return 2147483647; 23 else 24 return res; 25 26 } 27 };
---------------------------------------------------------------------------------------------分割线--------------------------------------------------------------------------------
30、Substring with Concatenation of All Words
题目:
首先得弄懂题目的意思,这道题看了很久才弄明白题目意思:也就是说,给定一个字符串数组,数组中的字符串不管以什么顺序拼接在一起,得到新的字符串new,然后在s中查找new在s中第一次出现的下标,题目给的例子可以拼接成foobar或者barfoo,然后判断其起始下标分别为9,0;
按照上面说的,可以做n!次拼接,然后通过kmp算法判断在s中出现的下标,但是这种方式的效率太低,得想想其他方法,降低算法时间复杂度;
想了一会,想到了一个解决该问题的方法:依次遍历字符串s,第i(i从0开始)轮遍历时,也就是从s的s[i]开始,依次截取子字符串,截取长度为一个word的长度,然后判断words数组中是否有当前子字符串,如果没有,i++,如果存在,再从i+word.length处截取子字符串,以此类推;再判断子字符串是否存在时,可以通过一个map统计每个word出现的次数,遍历时,出现一个word,则对应次数加1,具体看代码实现:
1 class Solution { 2 public: 3 vector<int> findSubstring(string S, vector<string> &L) { 4 int l_size = L.size(); 5 6 if (l_size <= 0) { 7 return vector<int>(); 8 } 9 10 vector<int> result; 11 map<string, int> word_count; 12 int word_size = L[0].size(); 13 int i, j; 14 15 for (i = 0; i < l_size; ++i) { 16 ++word_count[L[i]]; 17 } 18 19 map<string, int> counting; 20 21 for (i = 0; i <= (int)S.length() - (l_size * word_size); ++i) { 22 counting.clear(); 23 24 for (j = 0; j < l_size; ++j) { 25 string word = S.substr(i + j * word_size, word_size); 26 27 if (word_count.find(word) != word_count.end()) { 28 ++counting[word]; 29 30 if (counting[word] > word_count[word]) { 31 break; 32 } 33 } 34 else { 35 break; 36 } 37 } 38 39 if (j == l_size) { 40 result.push_back(i); 41 } 42 } 43 44 return result; 45 } 46 };