劍指offer(四)C++版

1.合併兩個排序的鏈表

  輸入兩個單調遞增的鏈表,輸出兩個鏈表合成後的鏈表,當然我們需要合成後的鏈表滿足單調不減規則

首先了解到的要點就是需要合併兩個已經排序後的鏈表,因此就有兩種選擇:①創建第三條鏈表,同時對兩條原始鏈表的元素從頭開始進行比較然後將得到的元素壓入新鏈表直到某一條鏈表結束,將剩下的鏈表接上即可②在兩條原始鏈表的基礎上進行元素的處理,即選擇長鏈表作爲最終返回值,將短鏈表中的元素壓入長鏈表,處理好前後之間的關係即可

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
	ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
	{
		ListNode* newlist;

		if (pHead1 == pHead2 || pHead2 == NULL)
		{
			return pHead1;//兩條鏈表相同或者第二條鏈表爲空
		}
		else if (pHead1 == NULL) {
			return pHead2;//第一條鏈表爲空
		}
		else//兩條鏈表都不爲空
		{
			if (pHead1->val < pHead2->val)//第一條鏈表的值小於第二條鏈表的值
			{
				newlist = pHead1;//插入第一條鏈表的元素
				newlist->next = Merge(pHead1->next, pHead2);
			}
			else//第一條鏈表的值大於第二條鏈表的值
			{
				newlist = pHead2;//插入第二條鏈表的元素
				newlist->next = Merge(pHead1, pHead2->next);
			}
		}
		return newlist;
	}
};

鏈接:合併兩個排序的鏈表

2.樹的子結構

  輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)

查找A樹中是否存在和B樹結構一致的子結構,可分爲兩方面:①在A樹中找到和B樹的根節點的值一致的節點C②然後判斷A樹中以C爲根節點的子樹是否包含和B樹一致的結構
第一步在A樹中查找和B樹根節點一致的節點,實質就是樹的遍歷,鑑於二叉樹的結構特點選用遞歸的方法進行遍歷,當找到相應節點後進行第二步處理
第二步判斷A樹中以C節點爲根節點的子樹中是否包含和B樹具有相同的結構,利用遞歸,若界節點C的值和B樹不一致,則返回false,若一致,則遞歸判斷它們各自的左右節點,直至A樹或B樹的葉節點

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    //其次,當找着R後,判斷Tree1中以R爲跟節點的樹和Tree2結構是否相同,以Tree1和Tree2的空節點爲限
    bool Tree1hasTree2(TreeNode* p1, TreeNode* p2)
    {
        if (p2 == nullptr)
            return true;
 
        if (p1 == nullptr)
            return false;
 
        if (p1->val != p2->val)
            return false;
 
        return Tree1hasTree2(p1->left, p2->left) && Tree1hasTree2(p1->right, p2->right);
    }
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        //首先在Root1中查找Root2的根結點相同的節點R
        bool result = false;
 
        if (pRoot1 != nullptr && pRoot2 != nullptr)
        {
            if(pRoot1->val == pRoot2->val)
                result = Tree1hasTree2(pRoot1, pRoot2);
 
            if (!result)
                result = HasSubtree(pRoot1->left, pRoot2);
            if (!result)
                result = HasSubtree(pRoot1->right, pRoot2);
        }
         
        return result;
    }
};
/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {
        if(pRoot1 == NULL || pRoot2 == NULL) return false;
        if(pRoot1->val == pRoot2->val && MyHasSubtree(pRoot1, pRoot2)) {    // 找到與根相同的結點才往下判斷
            return true;
        }
        return HasSubtree(pRoot1->left, pRoot2) || HasSubtree(pRoot1->right, pRoot2);   // 查找A的左右子樹是不是含有B樹
    }

    bool MyHasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {
        if(pRoot2 == NULL) return true; // B樹匹配到葉子結點了,說明B是A的子結構
        if(pRoot1 == NULL) return false;    // B沒到葉子結點,A就已經到了葉子結點,說明B還沒匹配完
        if(pRoot1->val == pRoot2->val) {
            return MyHasSubtree(pRoot1->left, pRoot2->left) && MyHasSubtree(pRoot1->right, pRoot2->right);
        }
        return false;
    }
};
3.二叉樹的鏡像

  操作給定的二叉樹,將其變換爲源二叉樹的鏡像

在這裏插入圖片描述
 首先根據提供的信息觀察特點,對比源二叉樹和鏡像二叉樹,可以發現根結點相同;鏡像二叉樹第二層交換了源二叉樹根節點的兩個子結點;鏡像二叉樹第三層即使在上一步的基礎上進一步交換每個含葉結點的左右結點。
 根據上面的特點可以總結到:先前序遍歷二叉樹的每個結點,如過遍歷到的結點有子結點,就交換它的兩個子結點,直至交換完所有的非葉子節點的左右結點後即可得到鏡像二叉樹

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    void Mirror(TreeNode *pRoot) {
    // 空節點
        if(pRoot==nullptr)
            return;
 
        // 葉子結點
        if(pRoot->left==nullptr&&pRoot->right==nullptr)
            return;
 
        // 二叉樹有多個節點時,交換當前節點的左右節點
        TreeNode* temp = pRoot->left;
        pRoot->left = pRoot->right;
        pRoot->right = temp;
         
        // 二叉樹的遍歷
        Mirror(pRoot->left);
        Mirror(pRoot->right);
    }
};
4.順時針打印矩陣

  輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每一個數字,例如,如果輸入如下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.

1  2  3  4
5  6  7  8
9  10  11 12
13 14 15 16

針對這道題,沒有特別的數據結構和高級的算法,考慮到的也即是此題中需要用到多次循環以及判斷多個邊界條件。因此我們首先考慮特殊情況:單行及單列。然後在考慮一般情況:首先計算需要打印幾圈,計算出行rows列cols的較小值min,若min爲偶數則圈數爲:layers = min / 2;min爲奇數則圈數爲:layers = min / 2 + 1;然後再控制循環一圈一圈的打印數字

class Solution {
public:
	vector<int> printMatrix(vector<vector<int> > matrix) {
		int cols = matrix[0].size();
		int rows = matrix.size();

		vector<int> res;

		if (cols == 1)//單列
		{
			for (int i = 0; i < rows; i++)
			{
				res.push_back(matrix[i][0]);
			}
			return res;
		}
		if (rows == 1)//單行
		{
			for (int i = 0; i < cols; i++)
			{
				res.push_back(matrix[0][i]);
			}
			return res;
		}

		int start1 = 0;
		int start2 = 0;
		int end1 = rows;
		int end2 = cols;
		int layers = 0;
		int max = rows;
		int min = cols;

		if (cols > rows)
		{
			swap(max, min);
		}
		if (min % 2 == 0)
		{
			layers = min / 2;
		}
		else
		{
			layers = min / 2 + 1;//圈數
		}

		for (int i = start1; i < end1; i++)
		{
			int flag = 0;//順時針轉一圈的每一個組成都是不可缺少的
			//從左到右
			for (int j = start2; j < end2; j++)
			{
				res.push_back(matrix[i][j]);
				flag = 1;
			}
			//從上到下,要想無從上到下的元素必須確保從左到右的元素已經被取過
			if (flag == 1)
			{
				for (int j = i + 1; j < end1; j++)
				{
					res.push_back(matrix[j][end2 - 1]);
					flag = 2;
				}
			}
			//從右到左
			if (flag == 2)
			{
				for (int j = end2 - 1 - 1; j >= i; j--)
				{
					res.push_back(matrix[end1 - 1][j]);
					flag = 3;
				}
			}
			//從下到上
			if (flag == 3)
			{
				for (int j = end1 - 1 - 1; j > i; j--)
				{
					res.push_back(matrix[j][i]);
				}
			}

			start1++;
			start2++;
			end1--;
			end2--;
			layers--;
			if (layers == 0)
			{
				break;
			}
		}
		return res;
	}
};
5.包含min函數的棧

  定義棧的數據結構,請在該類型中實現一個能夠得到棧中所含最小元素的min函數(時間複雜度應爲O(1))。
注意:保證測試中不會當棧爲空的時候,對棧調用pop()或者min()或者top()方法。

題目要求時間複雜度爲O(1), 就需要我們考率很多的設計, 若是用一個變量存儲最小值那麼噹噹前最小元素出棧後,無法獲得下一個最小的元素,因此需要用一個輔助棧進行數據的保存,當我們每次把最小元素壓入輔助棧,就能保證輔助棧的棧頂一直是最小元素,當最小元素從數據棧內彈出後,同時彈出輔助棧的棧頂元素,此時輔助棧的棧頂元素就是下一個最小值

步驟 操作 數據棧 輔助棧 最小值
1 壓入3 3 3 3
2 壓入4 3,4 3,3 3
3 壓入2 3,4,2 3,3,2 2
4 壓入1 3,4,2,1 3,3,2,1 1
3 彈出 3,4,2 3,3,2 2
3 彈出 3,4 3,3 3
3 壓入0 3,4,0 3,3,0 0
#include <stack>
class Solution {
public:
    void push(int value) {
        ordin_stack.push(value);
         
        if(min_stack.empty() || value <= min_stack.top())
        {
            min_stack.push(value);
        }
    }
    void pop() {
        if(ordin_stack.top() == min_stack.top())
        {
            ordin_stack.pop();
            min_stack.pop();
        }
        else{
            ordin_stack.pop();
        }
    }
    int top() {
            return ordin_stack.top();
    }
    int min() {
        return min_stack.top();
    }
private:
    std::stack<int> ordin_stack;
     
    std::stack<int> min_stack;
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章