//數字在排序數組中出現的次數
//求數字第一次出現的位置
int GetFirstK(int*
data, int length, int k, int start, int end)
{
if (start
> end)
return -1;
int middleIndex
= start + (end - start) / 2;//該求平均數的方法可以防止大小越界的問題
int middleData
= data[middleIndex];//找到中間的數字
if (middleData
== k){
if ((middleIndex
> 0 && data[middleIndex - 1] != k)\
|| middleIndex == 0)//如果中間的數字是第一個出現的該數字
或只有一個數字
return middleIndex;//返回第一個該數字的位置
else
end = middleIndex - 1;//如果不是說明
還要在前半部分找第一個
}
else if (middleData
> k)
end = middleIndex - 1;
else
start = middleIndex + 1;
return GetFirstK(data,length,k,start,end);
}
//同理求最後的位置
int GetLastK(int*
data, int length, int k, int start, int end)
{
if (start
> end)
return -1;
int middleIndex
= start + (end - start) / 2;
int middleData
= data[middleIndex];
if (middleData
== k){
if ((middleIndex
< length - 1 && data[middleIndex + 1] != k)\
|| middleIndex == length - 1)
return middleIndex;
else
start = middleIndex + 1;
}
else if (middleData
> k)
end = middleIndex - 1;
else
start = middleIndex + 1;
}
//知道了該數字第一次和最後一次出現的位置 將兩個位置相減加一就是出現的個數
int GetNumberOfK(int*
data, int length, int k)
{
int number
= 0;
if (data
!= NULL &&
length > 0){//處理特殊情況
int first
= GetFirstK(data,
length, k, 0, length - 1);
int last
= GetLastK(data,
length, k, 0, length - 1);
if (first
>= 0 && last >= 0)
number = last - first + 1;
}
return number;
}
- 一個數組裏除了兩個數字之外,其他數字都出現了偶數次。請找出這兩隻只出現了一次的數字。要求時間複雜度O(n) 空間複雜度O(1)
{2,4,3,6,3,2,5,5,} 輸出 4,6
如果本問題是數組中只出現了一個只出現一次的數字 就簡單了 。
大家知道 任何數對自己做按位異或運算是0 , 0按位異或任何數是任何數 把所有數字異或在一起最終的結果就是答案。
可是現在題目是有兩個只出現一次的數。
這裏知識遷移------ 把一個數組分成邏輯上的兩部分 每部分包涵一個只出現一次的數
首先按位異或全部元素 最終結果是兩個孤獨的數異或的結果
之後 抓住該數是‘1’一位的 以這一位是一還是零 把數組分成邏輯上的兩組
//找數組中只出現一次的數字 數組中其他數字均出現了兩次 有兩個數字只出現了一次
//在整數num的二進制位中找最低的是1的位
unsigned int FindFirstBitIs1(int num)
{
int indexBit
= 0;
while (((num
& 1) == 0) && (indexBit < 8 * sizeof(int)))
{
num = num >> 1;
++indexBit;
}
return indexBit;
}
//查看 num的二進制表示中從右邊數起的indexBit位是不是1
bool IsBit1(int num, unsigned int indexBit)
{
num = num >> indexBit;
return (num
& 1);
}
void FindNumsAppearOnce(int data[], int length)
{
if (data
== NULL || length < 2)
return ;
int result
= 0;
for (size_t i
= 0; i < length; ++i)
result ^= data[i];
unsigned int indexOf1
= FindFirstBitIs1(result);
int num1
= 0;
int num2
= 0;
for (int j
= 0; j < length; ++j){
if (IsBit1(data[j],
indexOf1))
num1 ^= data[j];
else
num2 ^= data[j];
}
cout << num1 << "
" << num2 << endl;
}
- 旋轉句子問題 把流傳很廣的 反轉句子問題轉化成 先總體逆置後逐個單詞逆置
左旋字符串問題 先逆置左右兩部分後逆置整體
//翻轉單詞順序 左旋字符串
//1.
void Reverse(char*
pBegin, char* pEnd)
{
if (pBegin
== NULL || pEnd == NULL)
return;
while (pBegin
< pEnd){
char temp
= *pBegin;
*pBegin = *pEnd;
*pEnd = temp;
pBegin++;
pEnd--;
}
}
char* ReverseSentencs(char*
pData)
{
if (pData
== NULL)
return NULL;
char*
pBegin = pData;
char*
pEnd = pData;
while (*pEnd
!= '\0'){
++pEnd;
}
--pEnd;
Reverse(pBegin,
pEnd);
pBegin = pEnd = pData;
while (*pBegin
!= '\0'){
if (*pBegin
== ' '){
pBegin++;
pEnd++;
}//爲什麼*pBegin
!= ‘、0’要在最前面判斷
//因爲否則下面三行代碼如果最先判斷會形成死循環
else if (*pEnd
== ' ' || *pEnd == '\0'){
Reverse(pBegin,
--pEnd);
pBegin = ++pEnd;
}
else{
pEnd++;
}
}
return pData;
}
//2.
char* LeftRotateString(char*
pStr, int n)
{
if (pStr
!= NULL){
int nLength
= static_cast<int>(strlen(pStr));
if (nLength
> 0 && n > 0 && n < nLength){
char*
pStrFS = pStr;
char*
pStrFE = pStr + n - 1;
char*
pStrSS = pStr + n;
char*
pStrSE = pStr + nLength - 1;
Reverse(pStrFS,
pStrFE);
Reverse(pStrSS,
pStrSE);
Reverse(pStr,
pStrSE);
}
}
return pStr;
}
4.
- 找出數組中和爲s的兩個數 找出數組中何爲s的連續所有數字 將其全部組合輸出出來
思路:
無序的數組很難處理 首先想到的是對數組排序 要找到其中的兩個數字 先取兩個初始值 排序後的第一個(最小值) 和第一個(最大值)
取到和之後 和s比較 大了最大值變成次大值 (倒數第二個數字) 小了最小值變成次小值 (第二個數字) 以此類推直到找到合適的兩個數
遷移到第二個問題上 現在求的是合爲s的多個數字之和 還是先排序 之後初始定義第一二個數字爲數字序列 若序列的和小於s擴充下一個更大的
數字爲序列的成員 若序列之和小於s除去序列中最小的(序列中位置前在第一個)數字爲數字序列成員 指直到找到合適的數字序列。
//和爲s的兩個數字 ------和爲s的連續正數序列
//1.找出數組中和爲s的兩個數字 找到了不同找其他的。
bool
FindNumBerWithSum(int
data[],
int
length,
int
sum,
int*
num1,
int*num2)
{
bool
found =
false;
if
(num1
==
NULL
||
num2
==
NULL
||
length
< 1)
return
found;
size_t
begin = 0;
size_t
end =
length
- 1;
while
(begin < end){
long
long
curSum =
data[begin] +
data[end];
if
(curSum ==
sum){
*num1
=
data[begin];
*num2
=
data[end];
found =
true;
break;
}
else
if
(curSum <
sum)
begin++;
else
end--;
}
return
found;
}
//----將此問題遷移到和爲s的連續整數序列
//輸入一個正數s,打印出所有和爲s的連續正數序列
void
Print(int
smal,
int
big)
{
for
(int
i =
smal; i <=
big; ++i)
cout << i ;
cout << endl;
}
void
FindContinuousSequence(int
sum)
{
if
(sum
< 3)
return;
int
smal = 1;
int
big = 2;
int
middle = (1 +
sum) / 2;
int
curSum = smal + big;//請注意這裏curSum是動態變化的 最初是1+2
while
(smal < middle){
if
(curSum ==
sum)
Print(smal, big);
while
(smal < middle && curSum >
sum){
curSum -= smal;
smal++;
if
(curSum ==
sum)
Print(smal, big);
}
big++;
curSum += big;
}
}