牛客網編程3

1

在數組中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。並將P1000000007取模的結果輸出。 即輸出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,要求不能使用乘除法、forwhileifelseswitchcase等關鍵字及條件判斷語句(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+1pattern+2

*>=2對應一次成功匹配,繼續匹配字符串的下一位是否匹配,str+1pattern不變

三者取或。即只要有一種情況能匹配成功認爲字符串就是匹配成功的。

對應2,相當於一次成功匹配,str+1pattern+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

一個鏈表中包含環,請找出該鏈表的環的入口結點。

/*

時間複雜度爲On),兩個指針,一個在前面,另一個緊鄰着這個指針,在後面。

兩個指針同時向前移動,每移動一次,前面的指針的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;

    }

 

};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章