劍指offer刷題記錄
阿新 • • 發佈:2019-02-04
- 連續子陣列的最大值
要求:例如:{6,-3,-2,7,-15,1,2,2},連續子向量的最大和為8(從第0個開始,到第3個為止)。給一個數組,返回它的最大連續子序列的和
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
int length = array.size();
int nCurSum = 0;
int nGreatSum = 0x80000000;//初始化和的最大值為負數
for(int i = 0; i < length; i ++)
{
if (nCurSum <= 0)//只有當和小於0時,才重新給和賦值
nCurSum = array[i];
else
nCurSum += array[i];
if(nCurSum > nGreatSum)
nGreatSum = nCurSum;
}
return nGreatSum;
}
};
2.陣列中出現次數超過一半以上的數字
要求:陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。例如輸入一個長度為9的陣列{1,2,3,2,2,2,5,4,2}。由於數字2在陣列中出現了5次,超過陣列長度的一半,因此輸出2。如果不存在則輸出0。
lass Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
int n = numbers.size();
if(n == 0) return 0;
int res = numbers[0], cnt = 1;
for(int i = 1; i < n; i ++)
{
if(res == numbers[i])
cnt ++;
else
cnt --;
if(cnt == 0)//重點在這裡,不用將i置為1開始了,因為之前已經比較過了,而且當cnt為0的時候,才會出現新出現的數字大於原來的數字的情況
{
res = numbers[i];
cnt = 1;
}
}
//確認一下選出來的數字確實是出現次數超過一半
int cnt_v = 0;
for(int i = 0; i < n; i ++)
{
if(res == numbers[i])
cnt_v ++;
}
if(cnt_v * 2 > n) return res;
return 0;
}
};
3、醜數
描述:把只包含質因子2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因為它包含質因子7。 習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。
思路:如果用暴力求解法,對每個數都判斷是否被2,3,5整除,效率比較低下。我們應該試著只對本來是醜數的數進行判斷,分別對第一個醜數*2,*3,*5操作,然後找出其最小的一個數,其必然就是第二個醜數,依次這樣迴圈下去,就可以找到第N個醜數
class Solution {
public:
int GetUglyNumber_Solution(int index) {
if(index == 0)
return 0;
int *pUglyNumbers = new int[index];
pUglyNumbers[0] = 1;
int nextUglyIndex = 1;
int *pMultiply2 = pUglyNumbers;
int *pMultiply3 = pUglyNumbers;
int *pMultiply5 = pUglyNumbers;
while(nextUglyIndex < index)
{
int min = MIN(*pMultiply2 * 2, *pMultiply3 * 3, *pMultiply5 * 5);
pUglyNumbers[nextUglyIndex] = min;
while(*pMultiply2 * 2 <= pUglyNumbers[nextUglyIndex])
++pMultiply2;
while(*pMultiply3 * 3 <= pUglyNumbers[nextUglyIndex])
++pMultiply3;
while(*pMultiply5 * 5 <= pUglyNumbers[nextUglyIndex])
++pMultiply5;
nextUglyIndex ++;
}
int uglyNumber = pUglyNumbers[nextUglyIndex - 1];
delete[] pUglyNumbers;
return uglyNumber;
}
int MIN(int a, int b, int c)
{
int min = (a < b)? a : b;
min = (min < c)? min : c;
return min;
}
};
3、第一個只出現一次的字元
描述:在一個字串(0<=字串長度<=10000,全部由字母組成)中找到第一個只出現一次的字元,並返回它的位置, 如果沒有則返回 -1.
思路:想必很多人跟我一樣,看到這種題就是暴力法,一個一個比較,如下
int FirstNotRepeatingChar(string str) {
char str_c;
int length = str.size();
int k = 1;
for(int i = 0; i < length; i ++)
{
str_c = str[i];
while(str[k] != str_c || k == i)
{
if(k == length - 1)
return i;
k++;
}
k = 0;
}
return -1;
}
這種時間複雜度為o(n2),顯然不太合適。而雜湊表正好可以派上用場,它的作用就是在記錄的儲存位置和它的關鍵字之間建立一個確定的對應關係,使得每個關鍵字對應一個儲存位置。
在這裡,是一個char型別的字元,8個位元組,因此總共只有256個字元。可以建立一個256大小的陣列,用來存放每個字元出現的次數。第二次迴圈則來尋找出現次數為1 的那個關鍵字。
//找到字串第一個不重複出現的字元
char FirstNotRepeatingChar(char* str) {
const int tablesize = 256;
unsigned int hasTable[tablesize ];
for(int i = 0; i < tablesize; i ++)
hasTable[i] = 0;
//儲存每個關鍵字出現的次數
char *pHashKey = str;
while(*(pHashKey) != '\0')
{
hadTable[*(pHashKey++)] ++;
}
//儲存結束
//找到關鍵字出現次數為1 的關鍵字
while(*(pHashKey) != '\0')
{
if(hadTable[*pHashKey] == 1)
{
return *pHashKey;
}
pHashKey ++;
}
return '\0';
}
4、兩個連結串列的第一個公共結點
描述:輸入兩個連結串列,找出它們的第一個公共結點。
所以,不要忽略他們有長有短,先要將起點設為一致,可以將長的一個連結串列讓其先走多的N步。
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
unsigned long length1 = GetListLong(pHead1);
unsigned long length2 = GetListLong(pHead2);
long nLengthDif = length1 - length2;
if(nLengthDif > 0)
{
for(int i = 0; i < nLengthDif; i ++)
pHead1 = pHead1->next;
}
else
{
for(int i = 0; i < (-nLengthDif); i ++)
pHead2 = pHead2->next;
}
while(pHead1 != pHead2&& pHead1 != NULL && pHead2!= NULL)
{
pHead1 = pHead1->next;
pHead2 = pHead2->next;
}
ListNode* pNode = pHead1;
return pNode;
}
unsigned long GetListLong(ListNode* pNode)
{
int cnt = 1;
while(pNode != NULL)
{
cnt++;
pNode = pNode->next;
}
return cnt;
}
};