剑指offer(刷题31-40)--c++,Python版本
文章目錄
- 目錄
- 第31 題:
- 解題思路:
- 代碼實現(xiàn):
- c++
- python
- 第32題:
- 解題思路:
- 代碼實現(xiàn):
- c++
- python
- 第33題:
- 解題思路:
- 代碼實現(xiàn):
- c++
- python
- 第34題:
- 解題思路:
- 代碼實現(xiàn):
- c++
- python
- 第35題:
- 解題思路:
- 代碼實現(xiàn):
- c++
- python
- 第36題:
- 解題思路:
- 代碼實現(xiàn):
- c++
- python
- 第37題:
- 解題思路:
- 代碼實現(xiàn):
- c++
- python
- 第38題:
- 解題思路:
- 代碼實現(xiàn):
- c++
- 遞歸實現(xiàn)
- python
- 第39題:
- 解題思路:
- 代碼實現(xiàn):
- c++
- python
- 第40題:
- 解題思路:
- 代碼實現(xiàn):
- c++
- python
目錄
第31 題:
輸入一個正整數(shù)數(shù)組,把數(shù)組里所有數(shù)字拼接起來排成一個數(shù),打印能拼接出的所有數(shù)字中最小的一個。例如輸入數(shù)組{3,32,321},則打印出這三個數(shù)字能排成的最小數(shù)字為321323。
解題思路:
代碼實現(xiàn):
c++
class Solution {public://比較兩個字符串大小的函數(shù),返回較小的那個字符串static bool cmp(int a,int b){string A="";string B="";A+=to_string(a);A+=to_string(b);B+=to_string(b);B+=to_string(a);return A<B;}//輸出最小的排序string PrintMinNumber(vector<int> numbers) {string answer="";sort(numbers.begin(),numbers.end(),cmp);//降序排序for(int i=0;i<numbers.size();i++){answer+=to_string(numbers[i]);}return answer;}};運行時間:2ms
占用內(nèi)存:480k
python
# -*- coding:utf-8 -*-第32題:
把只包含質(zhì)因子2、3和5的數(shù)稱作丑數(shù)(Ugly Number)。例如6、8都是丑數(shù),但14不是,因為它包含質(zhì)因子7。 習慣上我們把1當做是第一個丑數(shù)。求按從小到大的順序的第N個丑數(shù)。
解題思路:
- 個人想法:我們首先要定義一個判別一個數(shù)是否為丑數(shù)的函數(shù),而要判別一個數(shù)是否為丑數(shù)則只需要看其質(zhì)數(shù)因子是否都是2,3,5,如果有其他的肯定不是丑數(shù)。在定義好丑數(shù)的識別函數(shù)后,就可以定義一個函數(shù)輸出第N個丑數(shù)。
- 別人的想法:
通俗易懂的解釋:
首先從丑數(shù)的定義我們知道,一個丑數(shù)的因子只有2,3,5,那么丑數(shù)p = 2 ^ x * 3 ^ y * 5 ^ z,換句話說一個丑數(shù)一定由另一個丑數(shù)乘以2或者乘以3或者乘以5得到,那么我們從1開始乘以2,3,5,就得到2,3,5三個丑數(shù),在從這三個丑數(shù)出發(fā)乘以2,3,5就得到4,6,10,6,9,15,10,15,25九個丑數(shù),我們發(fā)現(xiàn)這種方法會得到重復的丑數(shù),而且我們題目要求第N個丑數(shù),這樣的方法得到的丑數(shù)也是無序的。那么我們可以維護三個隊列:
(1)丑數(shù)數(shù)組: 1
乘以2的隊列:2
乘以3的隊列:3
乘以5的隊列:5
選擇三個隊列頭最小的數(shù)2加入丑數(shù)數(shù)組,同時將該最小的數(shù)乘以2,3,5放入三個隊列;
(2)丑數(shù)數(shù)組:1,2
乘以2的隊列:4
乘以3的隊列:3,6
乘以5的隊列:5,10
選擇三個隊列頭最小的數(shù)3加入丑數(shù)數(shù)組,同時將該最小的數(shù)乘以2,3,5放入三個隊列;
(3)丑數(shù)數(shù)組:1,2,3
乘以2的隊列:4,6
乘以3的隊列:6,9
乘以5的隊列:5,10,15
選擇三個隊列頭里最小的數(shù)4加入丑數(shù)數(shù)組,同時將該最小的數(shù)乘以2,3,5放入三個隊列;
(4)丑數(shù)數(shù)組:1,2,3,4
乘以2的隊列:6,8
乘以3的隊列:6,9,12
乘以5的隊列:5,10,15,20
選擇三個隊列頭里最小的數(shù)5加入丑數(shù)數(shù)組,同時將該最小的數(shù)乘以2,3,5放入三個隊列;
(5)丑數(shù)數(shù)組:1,2,3,4,5
乘以2的隊列:6,8,10,
乘以3的隊列:6,9,12,15
乘以5的隊列:10,15,20,25
選擇三個隊列頭里最小的數(shù)6加入丑數(shù)數(shù)組,但我們發(fā)現(xiàn),有兩個隊列頭都為6,所以我們彈出兩個隊列頭,同時將12,18,30放入三個隊列;
……………………
疑問:
1.為什么分三個隊列?
丑數(shù)數(shù)組里的數(shù)一定是有序的,因為我們是從丑數(shù)數(shù)組里的數(shù)乘以2,3,5選出的最小數(shù),一定比以前未乘以2,3,5大,同時對于三個隊列內(nèi)部,按先后順序乘以2,3,5分別放入,所以同一個隊列內(nèi)部也是有序的;
2.為什么比較三個隊列頭部最小的數(shù)放入丑數(shù)數(shù)組?
因為三個隊列是有序的,所以取出三個頭中最小的,等同于找到了三個隊列所有數(shù)中最小的。
實現(xiàn)思路:
我們沒有必要維護三個隊列,只需要記錄三個指針顯示到達哪一步;“|”表示指針,arr表示丑數(shù)數(shù)組;
(1)1
|2
|3
|5
目前指針指向0,0,0,隊列頭arr[0] * 2 = 2, arr[0] * 3 = 3, arr[0] * 5 = 5
(2)1 2
2 |4
|3 6
|5 10
目前指針指向1,0,0,隊列頭arr[1] * 2 = 4, arr[0] * 3 = 3, arr[0] * 5 = 5
(3)1 2 3
2| 4 6
3 |6 9
|5 10 15
目前指針指向1,1,0,隊列頭arr[1] * 2 = 4, arr[1] * 3 = 6, arr[0] * 5 = 5
代碼實現(xiàn):
c++
class Solution { public:int GetUglyNumber_Solution(int index) {if (index < 7)return index;vector<int> res(index);res[0] = 1;int t2 = 0, t3 = 0, t5 = 0, i;for (i = 1; i < index; ++i){res[i] = min(res[t2] * 2, min(res[t3] * 3, res[t5] * 5));if (res[i] == res[t2] * 2)t2++;if (res[i] == res[t3] * 3)t3++;if (res[i] == res[t5] * 5)t5++;}return res[index - 1];} };運行時間:3ms
占用內(nèi)存:504k
python
# -*- coding:utf-8 -*-第33題:
在一個字符串(0<=字符串長度<=10000,全部由字母組成)中找到第一個只出現(xiàn)一次的字符,并返回它的位置, 如果沒有則返回 -1(需要區(qū)分大小寫).
解題思路:
- 使用字典結構存儲字母和字母出現(xiàn)的次數(shù),然后遍歷該字典,輸出只出現(xiàn)一次的字母的第一個便是我們需要的答案
代碼實現(xiàn):
c++
class Solution { public:int FirstNotRepeatingChar(string str) {map<char, int> mp;for(int i = 0; i < str.size(); ++i)mp[str[i]]++;for(int i = 0; i < str.size(); ++i){if(mp[str[i]]==1)return i;}return -1;} };運行時間:4ms
占用內(nèi)存:476k
python
由于Python中的字典是keys是無序的所以不好用于實現(xiàn)
# -*- coding:utf-8 -*-第34題:
在數(shù)組中的兩個數(shù)字,如果前面一個數(shù)字大于后面的數(shù)字,則這兩個數(shù)字組成一個逆序對。輸入一個數(shù)組,求出這個數(shù)組中的逆序對的總數(shù)P。并將P對1000000007取模的結果輸出。 即輸出P%1000000007
解題思路:
代碼實現(xiàn):
c++
python
# -*- coding:utf-8 -*-第35題:
輸入兩個鏈表,找出它們的第一個公共結點。
解題思路:
- 初步想法:
- 暴力解法:通過2層for循環(huán)遍歷兩個鏈表,然后找到第一個公共節(jié)點,然后打印出來。
公共結點的意思是兩個鏈表相遇之后后面都是一樣的,我還以為是交叉的兩個鏈表
代碼實現(xiàn):
c++
class Solution { public:ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2) {int len1 = findListLenth(pHead1);int len2 = findListLenth(pHead2);if(len1 > len2){pHead1 = walkStep(pHead1,len1 - len2); //如果鏈表1比較長,則讓鏈表1將差值走掉}else{pHead2 = walkStep(pHead2,len2 - len1);}while(pHead1 != NULL){if(pHead1 == pHead2) return pHead1; //如果找到了相同的節(jié)點,則返回pHead1 = pHead1->next;pHead2 = pHead2->next;}return NULL;}int findListLenth(ListNode *pHead1){if(pHead1 == NULL) return 0;int sum = 1;while(pHead1 = pHead1->next) sum++;return sum;}//讓鏈表遍歷走step步ListNode* walkStep(ListNode *pHead1, int step){while(step--){pHead1 = pHead1->next;}return pHead1;} };運行時間:3ms
占用內(nèi)存:376k
python
# -*- coding:utf-8 -*- class Solution:def getListLen(self,pHead):if pHead == None:return 0dataLen = 0while pHead != None:dataLen += 1pHead = pHead.nextreturn dataLendef FindFirstCommonNode(self, pHead1, pHead2):# write code heredataLen1 = self.getListLen(pHead1)dataLen2 = self.getListLen(pHead2)if dataLen1 > dataLen2:tempStep = dataLen1 - dataLen2while tempStep:pHead1 = pHead1.nexttempStep -= 1else:tempStep = dataLen2 - dataLen1while tempStep:pHead2 = pHead2.nexttempStep -= 1while pHead1!= None:if pHead1==pHead2:return pHead1pHead1 = pHead1.nextpHead2 = pHead2.next運行時間:30ms
占用內(nèi)存:5720k
第36題:
統(tǒng)計一個數(shù)字在排序數(shù)組中出現(xiàn)的次數(shù)。
解題思路:
- 從題目中,我們可以看到是對一個排序數(shù)據(jù)的查找問題,但是又和純粹的查找問題不同,我們可以使用二分查找的方法,但是?改進,因為題目中是找某個數(shù)字出現(xiàn)的次數(shù),只要找到了這個數(shù)字,向前,向后遍歷便可以統(tǒng)計出數(shù)字的出現(xiàn)次數(shù)。
代碼實現(xiàn):
c++
class Solution { public:int GetNumberOfK(vector<int> data ,int k) {if(data.size() <= 0){return 0;}int start = 0;int end = data.size() - 1;int dataIndex = -1; //保存查找該數(shù)的位置//使用二分查找對該數(shù)進行查找while(start <= end){int mid = (start + end) * 0.5;if(k == data[mid]){dataIndex = mid;break;}else if(k > data[mid]){start = mid + 1;}else{end = mid - 1;}}//如果沒有找到該數(shù),直接返回0if(dataIndex == -1){return 0;}//向左邊進行查找int dataCount = 1;int tempIndex = dataIndex - 1;while(tempIndex >= 0){if(data[tempIndex] != k){break;}tempIndex--;dataCount++;}//向右邊進行查找tempIndex = dataIndex + 1;while(tempIndex < data.size()){if(data[tempIndex] != k){break;}tempIndex++;dataCount++;}return dataCount;} };運行時間:4ms
占用內(nèi)存:376k
python
# -*- coding:utf-8 -*- class Solution:def GetNumberOfK(self, data, k):# write code hereif len(data) <= 0:return 0tempDict = {}for i in data:if i not in tempDict.keys():tempDict[i] = 1else:tempDict[i] += 1if k not in tempDict.keys():return 0else:return tempDict[k]運行時間:29ms
占用內(nèi)存:5680k
第37題:
輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經(jīng)過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度為樹的深度。
解題思路:
- 初步思想:這是一個樹的前序遍歷的算法題,我們只需要廣度優(yōu)先遍歷該樹,然后用一個數(shù)組記錄下每次運行到葉子節(jié)點的路徑長度,最后將路徑進行排序即可,取出路徑最長的那個即可。
代碼實現(xiàn):
c++
class Solution { public:int TreeDepth(TreeNode* pRoot){if (!pRoot) return 0;queue<TreeNode*> que;que.push(pRoot);int depth=0;while (!que.empty()) {int size=que.size();depth++;for (int i=0;i<size;i++) { //一次處理一層的數(shù)據(jù)TreeNode *node=que.front();que.pop();if (node->left) que.push(node->left);if (node->right) que.push(node->right);}}return depth;} };運行時間:3ms
占用內(nèi)存:372k
遞歸版本
#include <algorithm> class Solution { public:int TreeDepth(TreeNode* pRoot){if (!pRoot) return 0;return max(1+TreeDepth(pRoot->left) , 1+TreeDepth(pRoot->right));} };運行時間:3ms
占用內(nèi)存:460k
python
遞歸版本
# -*- coding:utf-8 -*- class Solution:def TreeDepth(self, pRoot):# write code hereif pRoot == None:return 0return max(self.TreeDepth(pRoot.left) + 1,self.TreeDepth(pRoot.right) + 1)運行時間:23ms
占用內(nèi)存:5752k
第38題:
輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。
解題思路:
- 初步思想:根據(jù)平衡二叉樹的性質(zhì),即每一棵樹的左右子樹高度差必須在1之內(nèi),所以可以轉換為一個查看每個子樹的其左右子樹的深度問題,如果深度的差在1以內(nèi),則為平衡二叉樹。可以使用遞歸的做法!
代碼實現(xiàn):
c++
遞歸實現(xiàn)
#include <algorithm> class Solution { public://返回樹的最大的深度int treeMaxDepth(TreeNode* root){if(root==NULL) return 0;return 1 + max(treeMaxDepth(root->left),treeMaxDepth(root->right));}bool IsBalanced_Solution(TreeNode* pRoot) {if(pRoot==NULL) return true; return abs(treeMaxDepth(pRoot->left) - treeMaxDepth(pRoot->right)) <= 1 && IsBalanced_Solution(pRoot->right) && IsBalanced_Solution(pRoot->left);} };運行時間:11ms
占用內(nèi)存:616k
python
# -*- coding:utf-8 -*- class Solution:def treeMaxDepath(self , pRoot):if pRoot == None:return 0return 1 + max(self.treeMaxDepath(pRoot.left) ,self.treeMaxDepath(pRoot.right) )def IsBalanced_Solution(self, pRoot):# write code hereif pRoot == None:return Truereturn abs(self.treeMaxDepath(pRoot.left) - self.treeMaxDepath(pRoot.right)) <=1 and self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right)運行時間:36ms
占用內(nèi)存:5672k
第39題:
一個整型數(shù)組里除了兩個數(shù)字之外,其他的數(shù)字都出現(xiàn)了偶數(shù)次。請寫程序找出這兩個只出現(xiàn)一次的數(shù)字。
解題思路:
- 初步的思路:使用hash map對數(shù)字出現(xiàn)的頻率進行統(tǒng)計,遍歷完數(shù)組也就統(tǒng)計完成,然后找出hash map中出現(xiàn)次數(shù)為1的兩個數(shù)即可。
代碼實現(xiàn):
c++
class Solution { public:void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {if(data.size()<2)return ;int size=data.size();int temp=data[0];for(int i=1;i<size;i++)temp=temp^data[i];if(temp==0)return ;int index=0;while((temp&1)==0){temp=temp>>1;++index;}*num1=*num2=0;for(int i=0;i<size;i++){if(IsBit(data[i],index))*num1^=data[i];else*num2^=data[i];}}bool IsBit(int num,int index){num=num>>index;return (num&1);} };運行時間:3ms
占用內(nèi)存:488k
python
# -*- coding:utf-8 -*- class Solution:# 返回[a,b] 其中ab是出現(xiàn)一次的兩個數(shù)字def FindNumsAppearOnce(self, array):# write code heretempDict = {}resultList = []for i in array:if i in tempDict.keys():tempDict[i] += 1else:tempDict[i] = 1for keys , values in tempDict.items():if values == 1:resultList.append(keys)return resultList運行時間:38ms
占用內(nèi)存:5856k
第40題:
小明很喜歡數(shù)學,有一天他在做數(shù)學作業(yè)時,要求計算出9~16的和,他馬上就寫出了正確答案是100。但是他并不滿足于此,他在想究竟有多少種連續(xù)的正數(shù)序列的和為100(至少包括兩個數(shù))。沒多久,他就得到另一組連續(xù)正數(shù)和為100的序列:18,19,20,21,22。現(xiàn)在把問題交給你,你能不能也很快的找出所有和為S的連續(xù)正數(shù)序列? Good Luck!
解題思路:
- 暴力法:時間復雜度為O(N^2)。分別計算以1開頭的和為100的遞增數(shù)列,然后計算以2開頭的和為100的遞增數(shù)列,依次類推。
- 參考其他人的:
1)由于我們要找的是和為S的連續(xù)正數(shù)序列,因此這個序列是個公差為1的等差數(shù)列,而這個序列的中間值代表了平均值的大小。假設序列長度為n,那么這個序列的中間值可以通過(S / n)得到,知道序列的中間值和長度,也就不難求出這段序列了。
2)滿足條件的n分兩種情況:
n為奇數(shù)時,序列中間的數(shù)正好是序列的平均值,所以條件為:(n & 1) == 1 && sum % n == 0;
n為偶數(shù)時,序列中間兩個數(shù)的平均值是序列的平均值,而這個平均值的小數(shù)部分為0.5,所以條件為:(sum % n) * 2 == n.
3)由題可知n >= 2,那么n的最大值是多少呢?我們完全可以將n從2到S全部遍歷一次,但是大部分遍歷是不必要的。為了讓n盡可能大,我們讓序列從1開始,
根據(jù)等差數(shù)列的求和公式:S = (1 + n) * n / 2,得到.
最后舉一個例子,假設輸入sum = 100,我們只需遍歷n = 13~2的情況(按題意應從大到小遍歷),n = 8時,得到序列[9, 10, 11, 12, 13, 14, 15, 16];n = 5時,得到序列[18, 19, 20, 21, 22]
代碼實現(xiàn):
c++
class Solution { public:vector<vector<int> > FindContinuousSequence(int sum) {vector<vector<int>> resArray;vector<int> tempArray;int tempSum , j , i;for(i = 1 ; i < sum ; i++){tempSum = i;tempArray.clear();tempArray.push_back(i);for(j = i+1 ; j < sum ; j++){tempSum += j;tempArray.push_back(j);if(tempSum == sum){resArray.push_back(tempArray);break;} }}return resArray; } };運行時間:3ms
占用內(nèi)存:484k
python
# -*- coding:utf-8 -*- class Solution:def FindContinuousSequence(self, tsum):# write code hereresultList = []for i in range(1,tsum):tempSum = itempList = [i]for j in range(i+1,tsum):tempSum += jtempList.append(j)if tempSum == tsum:resultList.append(tempList)breakreturn resultList運行時間:25ms
占用內(nèi)存:5852k
總結
以上是生活随笔為你收集整理的剑指offer(刷题31-40)--c++,Python版本的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度学习(07)-- 经典CNN网络结构
- 下一篇: c++基础学习(09)--(数据抽象、数