1
在數組中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。並將P對1000000007取模的結果輸出。 即輸出P%1000000007
輸入描述:
題目保證輸入的數組中沒有的相同的數字
數據範圍:
對於%50的數據,size<=10^4
對於%75的數據,size<=10^5
對於%100的數據,size<=2*10^5
解析:本題主要是時間複雜度的問題。使用歸併排序,分到最後就是一個元素的情況,
1如果arry[i]>arry[j],因爲兩段數組都是有序的,所以arry[i]>arry[mid+1...j],這些都是逆序對,我們統計出的逆序對爲j-(mid+1)+1=j-mid。並且將大數arry[i]放入臨時數組temp[]當中,i往前移動
2如果arry[i]<arry[j],則將大數arry[j]放入temp[]中,j往前移
class Solution {
public:
int InversePairs(vector<int> data) {
if(data.size()<=1) return 0;//如果少於等於1個元素,直接返回0
int* copy=new int[data.size()];
//初始化該數組,該數組作爲存放臨時排序的結果,最後要將排序的結果複製到原數組中
for(unsigned int i=0;i<data.size();i++)
copy[i]=0;
//調用遞歸函數求解結果
int count=InversePairCore(data,copy,0,data.size()-1);
delete[] copy;//刪除臨時數組
return count;
}
//程序的主體函數
int InversePairCore(vector<int>& data,int*& copy,int start,int end)
{
if(start==end)
{
copy[start]=data[start];
return 0;
}
//將數組拆分成兩部分
int length=(end-start)/2;//這裏使用的下標法,下面要用來計算逆序個數;也可以直接使用mid=(start+end)/2
//分別計算左邊部分和右邊部分
int left=InversePairCore(data,copy,start,start+length)%1000000007;
int right=InversePairCore(data,copy,start+length+1,end)%1000000007;
//進行逆序計算
int i=start+length;//前一個數組的最後一個下標
int j=end;//後一個數組的下標
int index=end;//輔助數組下標,從最後一個算起
int count=0;
while(i>=start && j>=start+length+1)
{
if(data[i]>data[j])
{
copy[index--]=data[i--];
//統計長度
count+=j-start-length;
if(count>=1000000007)//數值過大求餘
count%=1000000007;
}
else
{
copy[index--]=data[j--];
}
}
for(;i>=start;--i)
{
copy[index--]=data[i];
}
for(;j>=start+length+1;--j)
{
copy[index--]=data[j];
}
//排序
for(int i=start; i<=end; i++) {
data[i] = copy[i];
}
//返回最終的結果
return (count+left+right)%1000000007;
}
};
2
輸入兩個鏈表,找出它們的第一個公共結點。
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2) {
ListNode *p1 = pHead1;
ListNode *p2 = pHead2;
while(p1!=p2){
p1 = (p1==NULL ? pHead2 : p1->next);
p2 = (p2==NULL ? pHead1 : p2->next);
}
return p1;
}
};
3
一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。
/*考慮過程:
首先我們考慮這個問題的一個簡單版本:一個數組裏除了一個數字之外,其他的數字都出現了兩次。請寫程序找出這個只出現一次的數字。
這個題目的突破口在哪裏?題目爲什麼要強調有一個數字出現一次,其他的出現兩次?我們想到了異或運算的性質:任何一個數字異或它自己都等於0 。也就是說,如果我們從頭到尾依次異或數組中的每一個數字,那麼最終的結果剛好是那個只出現一次的數字,因爲那些出現兩次的數字全部在異或中抵消掉了。
有了上面簡單問題的解決方案之後,我們回到原始的問題。如果能夠把原數組分爲兩個子數組。在每個子數組中,包含一個只出現一次的數字,而其它數字都出現兩次。如果能夠這樣拆分原數組,按照前面的辦法就是分別求出這兩個只出現一次的數字了。
我們還是從頭到尾依次異或數組中的每一個數字,那麼最終得到的結果就是兩個只出現一次的數字的異或結果。因爲其它數字都出現了兩次,在異或中全部抵消掉了。由於這兩個數字肯定不一樣,那麼這個異或結果肯定不爲0 ,也就是說在這個結果數字的二進制表示中至少就有一位爲1 。我們在結果數字中找到第一個爲1 的位的位置,記爲第N 位。現在我們以第N 位是不是1 爲標準把原數組中的數字分成兩個子數組,第一個子數組中每個數字的第N 位都爲1 ,而第二個子數組的每個數字的第N 位都爲0 。
現在我們已經把原數組分成了兩個子數組,每個子數組都包含一個只出現一次的數字,而其它數字都出現了兩次。因此到此爲止,所有的問題我們都已經解決。*/
public class 數組中只出現一次的數字 {
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
if(array==null ||array.length<2)
return ;
int temp = 0;
for(int i=0;i<array.length;i++)
temp ^= array[i];
int indexOf1 = findFirstBitIs(temp);
for(int i=0;i<array.length;i++){
if(isBit(array[i], indexOf1))
num1[0]^=array[i];
else
num2[0]^=array[i];
}
}
public int findFirstBitIs(int num){
int indexBit = 0;
while(((num & 1)==0) && (indexBit)<8*4){
num = num >> 1;
++indexBit;
}
return indexBit;
}
public boolean isBit(int num,int indexBit){
num = num >> indexBit;
return (num & 1) == 1;
}
}
4
彙編語言中有一種移位指令叫做循環左移(ROL),現在有個簡單的任務,就是用字符串模擬這個指令的運算結果。對於一個給定的字符序列S,請你把其循環左移K位後的序列輸出。例如,字符序列S=”abcXYZdef”,要求輸出循環左移3位後的結果,即“XYZdefabc”。是不是很簡單?OK,搞定它!
class Solution {
public:
string LeftRotateString(string str, int n) {
int len = str.length();
if(len == 0) return "";
n = n % len;
str += str;
return str.substr(n, len);
}
};
5
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。
class Solution {
public:
int Sum_Solution(int n) {
int ans = n;
ans && (ans += Sum_Solution(n - 1));
return ans;
}
};
6
寫一個函數,求兩個整數之和,要求在函數體內不得使用+、-、*、/四則運算符號。
class Solution {
public:
int Add(int num1, int num2)
{
if(num2==0)
return num1;
int sum=num1^num2;
int carry=(num1&)<<1;
return Add(sum,carry);
}
};
7
請實現一個函數用來匹配包括'.'和'*'的正則表達式。模式中的字符'.'表示任意一個字符,而'*'表示它前面的字符可以出現任意次(包含0次)。 在本題中,匹配是指字符串的所有字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"ab*ac*a"匹配,但是與"aa.a"和"ab*a"均不匹配
/*
思路:只有當模式串和字符串同時等於\0,纔可以認爲兩個串匹配。
在匹配中,對於每個位的匹配可以分爲三種情況
1、(相應位匹配||模式串爲.&&字符串不是\0)&&模式串下一位是*
2、(相應位匹配||模式串爲.&&字符串不是\0)&&模式串下一位不是*
3、相應位不匹配&&(模式位不爲.||字符串是\0)
對應1,最複雜。分爲*取0,*取1,*>=2三種情況。
*取0對應跳過當前匹配位,繼續尋找patter的下一個匹配位,str不變,pattern+2
*取1對應當前匹配位算一次成功匹配,str+1,pattern+2
*取>=2對應一次成功匹配,繼續匹配字符串的下一位是否匹配,str+1,pattern不變
三者取或。即只要有一種情況能匹配成功認爲字符串就是匹配成功的。
對應2,相當於一次成功匹配,str+1,pattern+1
對應3,匹配失敗,直接返回false
*/
class Solution {
public:
bool match(char* str, char* pattern)
{
if(str==NULL||pattern==NULL)
return false;
return matchCore(str,pattern);
}
bool matchCore(char* str, char* pattern)
{
if(*str=='\0'&&*pattern=='\0')
return true;
if(*str!='\0'&&*pattern=='\0')
return false;
if(*(pattern+1)=='*')
{
if(*pattern==*str||(*pattern=='.'&&*str!='\0'))
/*
matchCore(str,pattern+2):模式串未匹配
matchCore(str+1,pattern):模式串已經匹配成功,嘗試匹配下一個字符串
matchCore(str+1,pat+2):模式串已經成功匹配,並且不匹配下一個字符串內容 注意這裏 matchCore(str+1,pat+2)重複考慮了(代碼中已經去除),謝謝@chlq的指出 */
return matchCore(str+1,pattern)||matchCore(str,pattern+2);
else
return matchCore(str,pattern+2);
}
if(*str==*pattern||(*pattern=='.'&&*str!='\0'))
return matchCore(str+1,pattern+1);
return false;
}
};
8
一個鏈表中包含環,請找出該鏈表的環的入口結點。
/*
時間複雜度爲O(n),兩個指針,一個在前面,另一個緊鄰着這個指針,在後面。
兩個指針同時向前移動,每移動一次,前面的指針的next指向NULL。
也就是說:訪問過的節點都斷開,最後到達的那個節點一定是尾節點的下一個,
也就是循環的第一個。
這時候已經是第二次訪問循環的第一節點了,第一次訪問的時候我們已經讓它指向了NULL,
所以到這結束。
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if (!pHead->next)
return NULL;
ListNode* previous = pHead;
ListNode* front = pHead ->next;
while (front)
{
previous->next = NULL;
previous = front;
front = front->next;
}
return previous;
}
};
9
請實現一個函數,用來判斷一顆二叉樹是不是對稱的。注意,如果一個二叉樹同此二叉樹的鏡像是同樣的,定義其爲對稱的。
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot)
{
if (pRoot == NULL)
return true;
return f(pRoot->left,pRoot->right);
}
bool f(TreeNode *t1, TreeNode *t2) {
if (t1 == NULL && t2 == NULL)
return true;
if (t1 != NULL && t2 != NULL)
return t1->val == t2->val && f(t1->left,t2->right) && f(t1->right, t2->left);
return false;
}
};