1. 程式人生 > >牛客網劍指Offer C++題解

牛客網劍指Offer C++題解

【二維陣列中的查詢】:在一個二維陣列中(每個一維陣列的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        bool ret = false;
        if (array.size() == 0 || array[0].size() == 0) return ret;
        int row;
        int col;
        int rows = array.size();
        int cols = array[0].size();
        row = 0;
        col = cols-1;
        while(row < rows && col >= 0){
            if (array[row][col] == target){
                ret = true;
                break;
            }else if (array[row][col] > target){
                col--;
            }else{
                row++;
            }
        }
        return ret;
    }
};

坑:需要判斷vector為空的情況,不然會段錯誤......錯誤......誤......

 

【替換空格】:請實現一個函式,將一個字串中的每個空格替換成“%20”。例如,當字串為We Are Happy.則經過替換之後的字串為We%20Are%20Happy。

class Solution {
public:
	void replaceSpace(char *str, int length) {
		if (str == NULL || length == 0) return;
		int blankspacenum = 0;
		int i;
		for (i = 0; i < length; i++) {
			if (str[i] == ' ')
				blankspacenum++;
		}
		int newlen = length + blankspacenum * 2;
		if (newlen == length) return;

		while (newlen >= 0 && newlen > length) {
			if (str[length] == ' ') {
				str[newlen--] = '0';
				str[newlen--] = '2';
				str[newlen--] = '%';
				length--;
			}
			else {
				str[newlen] = str[length];
				newlen--;
				length--;
			}
		}
	}
};

本題最好在str的基礎上進行操作,不要new一塊新的記憶體或者將str指向新的一塊空間,可能會導致記憶體洩漏。

 

【從尾到頭列印連結串列】:輸入一個連結串列,按連結串列值從尾到頭的順序返回一個ArrayList。

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int>v;
        if (head == NULL || head->next == NULL) return v; 
        stack<int>s;
        ListNode* p = head;
        while(p){
            s.push(p->val);
            p = p->next;
        }
        while(!s.empty()){
            v.push_back(s.top());
            s.pop();
        }
        return v;
    }
};

 

【用兩個棧實現佇列】

class Solution
{
public:
    void push(int node) {
        while(!stack2.empty()) stack2.pop();
        while(!stack1.empty()){
            stack2.push(stack1.top());
            stack1.pop();
        }
        stack1.push(node);
        while(!stack2.empty()){
            stack1.push(stack2.top());
            stack2.pop();
        }
    }

    int pop() {
        if(!stack1.empty()){
            int ret = stack1.top();
            stack1.pop();
            return ret;
        }
        return -1;
    }

private:
    stack<int> stack1;
    stack<int> stack2;
};

 

【旋轉陣列的最小數字】:把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。 輸入一個非減排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。 例如陣列{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該陣列的最小值為1。 NOTE:給出的所有元素都大於0,若陣列大小為0,請返回0。

class Solution {
public:
	int minNumberInRotateArray(vector<int> rotateArray) {
		if (rotateArray.size() == 0) return 0;
		int left = 0;
		int right = rotateArray.size()-1;
		int mid;
		while (left < right) {
            if(right - left == 1){
                mid = rotateArray[right] > rotateArray[left] ? left:right;
                break;
            }
			mid = (left + right) / 2;
			if (rotateArray[mid] >= rotateArray[left])
				left = mid;
			else if(rotateArray[mid] <= rotateArray[right])
				right = mid;
		}
		return rotateArray[mid];
	}
};

陣列可以分成兩塊,每一塊都有序,可以用二分查詢的思想。

 

【斐波那契數列】:大家都知道斐波那契數列,現在要求輸入一個整數n,請你輸出斐波那契數列的第n項(從0開始,第0項為0)。n<=39

class Solution {
public:
    int Fibonacci(int n) {
        int a[39+3];
        a[0] = 0;
        a[1] = 1;
        a[2] = 1;
        int i;
        for(i=3;i<=n;i++){
            a[i] = a[i-1] + a[i-2];
        }
        return a[n];
    }
};

 

【跳臺階】:一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法(先後次序不同算不同的結果)。

class Solution {
public:
    int jumpFloor(int number) {
        if(number <= 1) return 1;
        else if (number == 2) return 2;
        int a = 1;
        int b = 2;
        int i;
        for (i=3;i<number;i++){
            int temp = b;
            b += a;
            a = temp;
        }
        return a+b;
    }
};

挺經典的題:假設n級臺階有F(n)種跳法,若第一跳為跳一個臺階,則剩下的n-1個臺階有F(n-1)種跳法,若第一跳是兩個臺階,則剩下的臺階有F(n-2)種跳法,同時等式F(n) = F(n-1) + F(n-2)成立(n>2)

 

【變態跳臺階】:一隻青蛙一次可以跳上1級臺階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。

class Solution {
public:
    int jumpFloorII(int number) {
        return pow(2,number-1);
    }
};

同上:F(n) = F(n-1) + F(n-2) + ... + F(1) + 1;

上式恰好是2^(n-1);

 

【矩形覆蓋】:我們可以用2*1的小矩形橫著或者豎著去覆蓋更大的矩形。請問用n個2*1的小矩形無重疊地覆蓋一個2*n的大矩形,總共有多少種方法?

class Solution {
public:
    int rectCover(int number) {
        if (number <= 2) return number;
        int a = 1;
        int b = 2;
        int i;
        for (i=3;i<number;i++){
            int temp = b;
            b += a;
            a = temp;
        }
        return a+b;
    }
};

思路與上面【跳臺階】的一樣:F(n) = F(n-1) + F(n-2)(n>2),F(n) = n(0<=n<=2)

 

【二進位制中1的個數】:輸入一個整數,輸出該數二進位制表示中1的個數。其中負數用補碼錶示。

class Solution {
public:
     int  NumberOf1(int n) {
         int ret = 0;
         while(n){
             n = n & (n-1);
             ret++;
         }
         return ret;
     }
};

n = n & (n-1)每次將最低位的1變為0

 

【數值的整數次方】:給定一個double型別的浮點數base和int型別的整數exponent。求base的exponent次方。

class Solution {
public:
    double Power(double base, int exponent) {
        if (exponent == 0) return 1.0;
        if (fabs(base - 0.0) < 0.0000001) return 0.0;
        int flag = 1;
        if (exponent < 0){
            flag = 0;
            exponent = (-exponent);
        }
        double res = 1.0;
        while(exponent--){
            res *= base;
        }
        if (flag)
            return res;
        else
            return 1.0/res;
    }
};

 

【調整陣列順序使奇數位於偶數前面】:輸入一個整數陣列,實現一個函式來調整該陣列中數字的順序,使得所有的奇數位於陣列的前半部分,所有的偶數位於陣列的後半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。

class Solution {
public:
    void reOrderArray(vector<int> &array) {
        int num1 = 0;
        for (auto x : array)
            if (x%2)
                num1++;
        
        int p1 = 0;
        int p2 = num1;
        int *a = new int [array.size()];
        for (auto x : array){
            if (x%2)
                a[p1++] = x;
            else
                a[p2++] = x;
        }
        
        int i;
        for (i=0;i<array.size();i++)
            array[i] = a[i];
        
        delete []a;
    }
};

 

【連結串列中倒數第k個結點】:輸入一個連結串列,輸出該連結串列中倒數第k個結點。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        int flag = 1;
        int i;
        ListNode* pRes = pListHead;
        for (i=0;i<k;i++){
            if (pListHead)
                pListHead = pListHead->next;
            else {
                flag = 0;
                break;
            }
        }
        if (flag == 0) return nullptr;
        
        while(pListHead){
            pListHead = pListHead->next;
            pRes = pRes->next;
        }
        return pRes;
    }
};

用兩個指標,一個指標先走k-1步(注意連結串列長度可能小於k),接著另一個指標從頭開始,第一個指標結束的時候,第二個指標就是倒數第k個。

 

【反轉連結串列】:輸入一個連結串列,反轉連結串列後,輸出新連結串列的表頭。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        if (pHead == nullptr || pHead->next == nullptr) 
            return pHead;
        
        ListNode* pCur = pHead;
        ListNode* pLast = nullptr;
        while(pCur){
            ListNode* temp = pCur->next;
            pCur->next = pLast;
            pLast = pCur;
            pCur = temp;
        }
        return pLast;
    }
};

 

【合併兩個排序的連結串列】:輸入兩個單調遞增的連結串列,輸出兩個連結串列合成後的連結串列,當然我們需要合成後的連結串列滿足單調不減規則。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1 == nullptr)
            return pHead2;
        if(pHead2 == nullptr)
            return pHead1;
        ListNode* pCur = nullptr;
        if(pHead1->val < pHead2->val){
            pCur = pHead1;
            pHead1 = pHead1->next;
        }else{
            pCur = pHead2;
            pHead2 = pHead2->next;
        }
        pCur->next = nullptr;
        ListNode* resHead = pCur;
        while(pHead1 && pHead2){
            if (pHead1->val < pHead2->val){
                pCur->next = pHead1;
                pCur = pHead1;
                pHead1 = pHead1->next;
                pCur->next = nullptr;
            }else{
                pCur->next = pHead2;
                pCur = pHead2;
                pHead2 = pHead2->next;
                pCur->next = nullptr;
            }
        }
        
        if (pHead1)
            pCur->next = pHead1;
        else if (pHead2)
            pCur->next = pHead2;
        return resHead;
    }
};

 

【順時針列印矩陣】:輸入一個矩陣,按照從外向裡以順時針的順序依次打印出每一個數字,例如,如果輸入如下4 X 4矩陣: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 則依次打印出數字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

class Solution {
public:
	vector<int> printMatrix(vector<vector<int> > matrix) {
		vector<int>v;
		if (matrix.size() == 0 || matrix[0].size() == 0)
			return v;

		if (matrix.size() == 1) {
			return matrix[0];
		}

		if (matrix[0].size() == 1) {
			for (auto x : matrix) {
				v.push_back(x[0]);
			}
			return v;
		}
		int rows = matrix.size();
		int cols = matrix[0].size();

		int row = 0;
		int col = 0;

		while (rows > 1 && cols > 1) {
			int trow = row;
			int tcol = col;
			char flag = 'r';
			while (1) {
				v.push_back(matrix[row][col]);
				switch (flag) {
				case 'r':
					col++;
					if (col == tcol + cols - 1)
						flag = 'd';
					break;
				case 'l':
					col--;
					if (col == tcol)
						flag = 'u';
					break;
				case 'u':
					row--;
					if (row == trow)
						flag = 'r';
					break;
				case 'd':
					row++;
					if (row == trow + rows - 1)
						flag = 'l';
					break;
				}
				if (row == trow && col == tcol)
					break;
			}
			row += 1;
			col += 1;
			rows -= 2;
			cols -= 2;
		}
		if (rows == 1) {
			int i;
			for (i = col; i < col + cols; i++)
				v.push_back(matrix[row][i]);
		}
		else if (cols == 1) {
			int i;
			for (i = row; i < row + rows; i++)
				v.push_back(matrix[i][col]);
		}
		return v;
	}
};

思路比較直白,每次列印一個圈的外層,當列印長度小於2的時候結束迴圈,處理長度為1的情況。

 

【包含min函式的棧】:定義棧的資料結構,請在該型別中實現一個能夠得到棧中所含最小元素的min函式(時間複雜度應為O(1))。

class Solution {
public:
    void push(int value) {
        s.push(value);
        if (minStack.empty())
            minStack.push(value);
        else{
            int min = minStack.top();
            min = min < value ? min:value;
            minStack.push(min);
        }
    }
    void pop() {
        s.pop();
        minStack.pop();
    }
    int top() {
        return s.top();
    }
    int min() {
        return minStack.top();
    }
    
private:
    stack<int> s;
    stack<int> minStack;
};

用兩個棧,其中一個儲存使用者資料,一個儲存著當前使用者資料的最小值的輔助棧。例如使用者壓入:5,6,1,12。那麼輔助棧為5,5,1,1。

 

【棧的壓入、彈出序列】:輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否可能為該棧的彈出順序。假設壓入棧的所有數字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。(注意:這兩個序列的長度是相等的)

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        if (pushV.size() == 0 || popV.size() == 0)
            return true;
        int pushPos = 0;
        int popPos = 0;
        stack<int> s;
        while(popPos < popV.size()){
            int key = popV[popPos++];
            if (!s.empty() && s.top() == key){
                s.pop();
                continue;
            }
            while(pushPos < pushV.size() && pushV[pushPos] != key){
                s.push(pushV[pushPos++]);
            }
            if (pushPos < pushV.size() && pushV[pushPos] == key){
                pushPos++;
                continue;
            }
            return false;
        }
        return true;
    }
};

用兩個棧模擬壓棧出棧過程。從出棧序列開始,如果棧頂不等於出棧序列,則繼續壓棧,若入棧序列已經找不到相應的入棧的整數時,則說明不可能存在這樣的出棧序列。若棧頂等於出棧序列,則退棧。

 

【從上往下列印二叉樹】:從上往下打印出二叉樹的每個節點,同層節點從左至右列印。

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        vector<int>v;
        if (root == nullptr)
            return v;
        queue<TreeNode*>s;
        s.push(root);
        while(!s.empty()){
            TreeNode* cur = s.front();
            s.pop();
            v.push_back(cur->val);
            if(cur->left)
                s.push(cur->left);
            if(cur->right)
                s.push(cur->right);
        }
        return v;
    }
};

樹的廣度優先遍歷,用佇列。。。

 

【二叉搜尋樹的後序遍歷序列】:輸入一個整數陣列,判斷該陣列是不是某二叉搜尋樹的後序遍歷的結果。如果是則輸出Yes,否則輸出No。假設輸入的陣列的任意兩個數字都互不相同。

class Solution {
public:
	bool VerifySquenceOfBST(vector<int> sequence) {
        if (sequence.size() == 0) 
            return false;
		return VerifySquenceOfBST(sequence, 0, sequence.size() - 1);
	}

	bool VerifySquenceOfBST(vector<int> sequence, int l, int r) {
        if (l >= r)
            return true;
		int key = sequence[r];
		int i;
		for (i = l; i < r; i++) {
			if (sequence[i] > key)
				break;
		}

		int j;
		for (j = i; j < r; j++) {
			if (sequence[j] < key)
				return false;
		}
		bool left = true;
		if (i > l) {
			left = VerifySquenceOfBST(sequence, l, i - 1);
		}

		bool right = true;
		if (i < r) {
			right = VerifySquenceOfBST(sequence, i, r-1);
		}
		return (left && right);
	}
};

步驟:

找到左子樹和右子樹,檢查右子樹有沒問題(左子樹肯定沒問題),有問題返回false,否則繼續遞迴,直到只剩下一個節點。

 

【二叉樹中和為某一值的路徑】:輸入一顆二叉樹的跟節點和一個整數,打印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。(注意: 在返回值的list中,陣列長度大的陣列靠前)

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        vector<int>tv;
        Dfs_FindPath(root,expectNumber,tv);
        return v;
    }
    
    void Dfs_FindPath(TreeNode* root,int expectNumber,
                                      vector<int>tv){
        if (root == nullptr)
            return ;
        
        tv.push_back(root->val);
        if (root->left)
            Dfs_FindPath(root->left,expectNumber,tv);
        if (root->right)
            Dfs_FindPath(root->right,expectNumber,tv);
        
        if(root->left == nullptr && root->right == nullptr){
            int sum = 0;
            for(auto x : tv)
                sum += x;
            if (sum == expectNumber)
                v.push_back(tv);
        }
        
    }

private:
    vector<vector<int> >v;
};

深度優先遍歷。。。

 

【複雜連結串列的複製】:輸入一個複雜連結串列(每個節點中有節點值,以及兩個指標,一個指向下一個節點,另一個特殊指標指向任意一個節點),返回結果為複製後複雜連結串列的head。(注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空)

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if (pHead == nullptr)
            return nullptr;
        
        RandomListNode* tHead = pHead;
        while(tHead){
            RandomListNode* newNode = new RandomListNode(tHead->label);
            newNode->next = tHead->next;
            tHead->next = newNode;
            tHead = newNode->next;
        }
        
        tHead = pHead;
        while(tHead){
            RandomListNode* temp = tHead->next;
            if(tHead->random)
                temp->random = tHead->random->next;
            else
                temp->random = nullptr;
            tHead = temp->next;
        }
        
        tHead = pHead;
        RandomListNode* pRes = tHead->next;
        RandomListNode* tpRes = pRes;
        while(tHead){
            tHead->next = pRes->next;
            if (tHead->next == nullptr){
                break;
            }
            pRes->next = tHead->next->next;
            tHead = tHead->next;
            pRes = pRes->next;
        }
        return tpRes;
    }
};

先在原連結串列的基礎上覆製出一份相同的連結串列(先忽略自由指標)例如A->A*->B->B*->C->C*,接著再處理自由指標。那麼奇數位的節點為原節點,偶數位的節點是複製連結串列節點。

 

【字串的排列】:輸入一個字串,按字典序打印出該字串中字元的所有排列。例如輸入字串abc,則打印出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba。

class Solution {
public:
	vector<string> Permutation(string str) {
		vector<string> v;
		if (str.size() == 0)
			return v;
		Permutation(str,0,v);
        sort(v.begin(),v.end());
		return v;
	}

	void Permutation(string str,int begin,vector<string>&v) {
		if (begin == str.length()-1) {
			v.push_back(str);
			return;
		}	
		int i;
		for (i = begin; i < str.length(); i++) {
			if (i != begin && str[i] == str[begin])    //重複不交換
				continue;
			swap(str[i], str[begin]);
			Permutation(str,begin+1,v);
			swap(str[i], str[begin]);        //恢復原樣
		}

	}
};

 

【陣列中出現次數超過一半的數字】:陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。例如輸入一個長度為9的陣列{1,2,3,2,2,2,5,4,2}。由於數字2在陣列中出現了5次,超過陣列長度的一半,因此輸出2。如果不存在則輸出0。

class Solution {
public:
	int MoreThanHalfNum_Solution(vector<int> numbers) {
		if (numbers.size() <= 0)
			return 0;
		int len = numbers.size();
		map<int, int>m;
		for (auto x : numbers) {
			auto iter = m.find(x);
			int l = 1;
			if (iter == m.end())
				m.insert(pair<int,int>(x, 1));
			else {
				iter->second = iter->second + 1;
				l = iter->second;
			}
			if (len / 2 < l)
				return x;
			
		}
		return 0;
	}
};

 

【連續子陣列的最大和】:HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如:{6,-3,-2,7,-15,1,2,2},連續子向量的最大和為8(從第0個開始,到第3個為止)。給一個數組,返回它的最大連續子序列的和,你會不會被他忽悠住?(子向量的長度至少是1)

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        int sum = array[0];
        int i;
        int max = -1000000000;
        for (i=1;i<array.size();i++){
            if (sum < 0)
                sum = array[i];
            else
                sum += array[i];
            if (sum > max)
                max = sum;
        }
        return max;
    }
};

主要前面累加的值為大於等於0時,對當前的數都是有正作用的。但一旦前面累加的為負,則應該拋棄。

 

【整數中1出現的次數(從1到n整數中1出現的次數)】:求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數(從1 到 n 中1出現的次數)。

class Solution {
public:
	int NumberOf1Between1AndN_Solution(int n)
	{
		int e = 10;
		int sum = 0;
		while (1) {
			int x = n / e;
			int y = n / (e / 10) % 10;
			if (y > 1)
				sum += x * (e / 10) + (e / 10);
			else if (y == 1)
				sum += x * (e / 10) + n % (e/10) + 1;
			else
				sum += x * (e / 10);
			e *= 10;
			if (x == 0) break;
		}
		return sum;
	}
};

從個位開始算起一直到最高位。對個位來說,數字從0-9不斷迴圈,例如213,個位 一共迴圈了20次,所以個位為1的數字一個有21+1=22個。對於十位為1是10-19,110-119,210-213,一共2*10+4=24個。對於百位為1是100-199,一共100個,所以一共:22+24+100=146個1。

 

【把陣列排成最小的數】:輸入一個正整數陣列,把數組裡所有數字拼接起來排成一個數,列印能拼接出的所有數字中最小的一個。例如輸入陣列{3,32,321},則打印出這三個數字能排成的最小數字為321323。

bool cmp(const int &a, const int &b) {
	stringstream ss1;
	ss1 << a << b;
	stringstream ss2;
	ss2 << b << a;
	return ss1.str() < ss2.str();
}
class Solution {
public:
	string PrintMinNumber(vector<int> numbers) {
		std::sort(numbers.begin(),numbers.end(),cmp);
		stringstream ss;
		for (auto x : numbers) {
			ss << x;
		}
		return ss.str();
	}
};

自定義排序方式,兩個數m和n,如果mn>nm,那麼排序方式是:nm,mn。

 

【醜數】:把只包含質因子2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因為它包含質因子7。 習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。

class Solution {
public:
    int GetUglyNumber_Solution(int index) {
        if (index <= 0)
            return 0;
        
        int* a = new int [index];
        a[0] = 1;
        int newindex = 1;
        int* p2 = a;
        int* p3 = a;
        int* p5 = a;
        while(newindex < index){
            a[newindex] = Mins(*p2*2,*p3*3,*p5*5);
            while(*p2*2 <= a[newindex])
                p2++;
            
            while(*p3*3 <= a[newindex])
                p3++;
            
            while(*p5*5 <= a[newindex])
                p5++;
            
            newindex++;
        }
        int res = a[index-1];
        delete []a;
        return res;
    }
    
    int Mins(int a,int b,int c){
        int min = a;
        min = min > b ? b : min;
        min = min > c ? c : min;
        return min;
    }
};

 

後一個醜數是前面醜數的某一個*2或*3或*5的結果。。。

 

【兩個連結串列的第一個公共結點】:輸入兩個連結串列,找出它們的第一個公共結點。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
	ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2) {
		if (pHead1 == nullptr || pHead2 == nullptr)
			return nullptr;

		set<void*>s;
		while (pHead1) {
			auto iter = s.find(pHead1);
			if (iter == s.end())
				s.insert(pHead1);

			pHead1 = pHead1->next;
		}

		while (pHead2) {
			auto iter = s.find(pHead2);
			if (iter != s.end())
				break;
			pHead2 = pHead2->next;
		}

		return pHead2;
	}
};

或:

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
	ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2) {
		if (pHead1 == nullptr || pHead2 == nullptr)
			return nullptr;

        ListNode* tpHead1 = pHead1;
        ListNode* tpHead2 = pHead2;
        int len1 = 0;
		while (tpHead1) {
			tpHead1 = tpHead1->next;
            len1++;
		}
        
        int len2 = 0;
		while (tpHead2) {
			tpHead2 = tpHead2->next;
            len2++;
		}
        
        //長的連結串列先走k步
        if (len1 > len2){
            int k = len1-len2;
            while(k--){
                pHead1 = pHead1->next;
            }
            
        }else{
            int k = len2-len1;
            while(k--){
                pHead2 = pHead2->next;
            }
        }
        
        while(pHead1 && pHead2 && pHead1 != pHead2){
                pHead1 = pHead1->next;
                pHead2 = pHead2->next;
        }
        return pHead1;
	}
};

 

 

未完持續。。。