剑指Offer66题之1-6

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/muyiyushan/article/details/88344674

第一题: 二维数组中的查找

题目

在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

解析

根据有序这个条件,可以逐行二分查找。时间复杂度为 O ( n l o g n ) O(nlogn)

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
    	// 逐行遍历
        for (int i = 0; i < (int)array.size(); i++)
        	// 二分查找
            if (binary_search(array[i].begin(), array[i].end(), target))
                return true;
        return false;
    }
};

左下角开始,当target比当前位置数值小,则往上查找,当target比当前位置数值大,则往右查找。时间复杂度为 O ( 2 n ) O(2n)

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
    	// n 为行数, m为列数
        int n = array.size(), m = array[0].size();
        // 初始位置,左下角(r,c)
        int r = n - 1, c = 0;
        // 当查询位置仍在数组范围内,即r>=0 && c<m
        while (r >= 0 && c < m)
        	// 找到target
            if (target == array[r][c])
                return true;
             // target小于当前位置数值,往上
            else if (target < array[r][c])
                --r;
            // 往右
            else
                ++c;
        return false; //没有查到
    }
};

备注

C++ STL 的二分查找函数: binary_search(arr[],arr[]+size,index),arr[]是起始位置,arr[]+size是结束位置,index是查找对象

第二题 : 替换空格

题目

请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

解析

1)求出空格数,2) 把str指向的空间容量扩大到能接纳替换后的字符串容量大小, 使用realloc函数,3) 然后从原始字符串的尾部把字符一个一个复制到扩容字符串的尾部,遇到空格就替换,只有从尾部开始才能保证数据不被覆盖。

class Solution{
public:
	void replaceSpace(char* str, int length){
		int cnt = 0; // 空格数
		int i = lenght -1;
		// 计算空格数
		for (int i = 0; i < length; cnt += (str[i++] == ' ')); 
		// 扩大str的内存空间,length变成新str的长度
		str = (char *)realloc(str, lenght += 2 * cnt);
		// 从后往前复制
		// j是新str长度-1,i是原str长度-1
		for (int j = length -1; i >=0; i--){
			if (str[i] != ' ')
				str[j--] = str[i];
			else
				str[j] = '0', str[j-1] = '2', str[j-2] = '%', j-=3;
		}
	}
}

备注

void *realloc (void *ptr, size_t new_size ) 修改一个原先已经分配的内存块的大小,可以使一块内存的扩大或缩小。当起始空间的地址为空,即ptr = NULL,则同malloc。当ptr非空:若nuw_size < size,即缩小ptr所指向的内存空间,该内存块尾部的部分内存被拿掉,剩余部分内存的原先内容依然保留;若nuw_size > size,即扩大ptr所指向的内存空间,如果原先的内存尾部有足够的扩大空间,则直接在原先的内存块尾部新增内存,如果原先的内存尾部空间不足,或原先的内存块无法改变大小,realloc将重新分配另一块nuw_size大小的内存,并把原先那块内存的内容复制到新的内存块上。因此,使用realloc后就应该改用realloc返回的新指针

第三题 : 从尾到头打印链表

题目:

输入一个链表,从尾到头打印链表每个节点的值。

解析:

两种做法:

  • 栈, 将链表存入栈内,再依次从栈内取出,Fist in last out
  • 递归
/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        stack<int> st; //定义栈
        // 存入栈
        while (head != nullptr)
            st.push(head->val), head = head->next;
        // 将stack中元素依次取出,存入vector    
        vector<int> ret;
        while (!st.empty())
            ret.push_back(st.top()), st.pop();
        return ret;
    }
};
class Solution{
public:
	vector<int> printListFromTailToHead(ListNode* head){
		vector<int> ret;
		dfs(head, ret);
		return ret;
	}
	void dfs(ListNode *head, vector<int> &ret){
		if (head == nullptr)
			return;
		dfs(head->next, ret);
		ret.push_back(head->val);
	}	
};

备注

stack , queue : push
list, vector : push_back

第四题 : 重建二叉树

题目

输入某二叉树的前序遍历中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

解析

利用前序遍历第一个数字为根,用这个根在中序遍历中查找,左边的就是左子树,右边的就是右子树,算出左右子树的长度,用其长度在前序遍历中划分出左右子树,重复上述过程,就可以重建这颗二叉树了。

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution{
public:
	TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin){
		// 如果为空,返回NULL
		if (pre.size() == 0)
			return NULL;
		// 递归函数dfs
		TreeNode * root = dfs(pre, vin, 0, pre.size(), 0, vin.size());
		return root;
	}
	TreeNode *dfs(vector<int> &pre,vector<int> &vin, int p_l, int p_r, int v_l, int v_r) {
        if (p_l == p_r)
            return NULL;
        // 前序遍历第一个元素为根节点    
        TreeNode *root = new TreeNode(pre[p_l]);
        // pos: 根节点在vin中位置
        int pos = -1;
        // 计算pos
        for (int i = v_l; i < v_r; i++)
            if (vin[i] == pre[p_l]) {
                pos = i;
                break;
            }
        // 划分左右子树,调用递归函数;其中,pos-v_l 为左子树长度        
        root->left = dfs(pre, vin, p_l + 1, p_l + 1 + pos - v_l, v_l, pos);
        root->right = dfs(pre, vin, p_l + 1 + pos - v_l, p_r, pos + 1, v_r);
        return root;
    }
};

备注

二叉树的遍历和重建都使用递归的思路,所以要明白在一个节点上如何操作
前序遍历:根节点 -> 左子树 ->右子树
中序遍历:左子树 ->根节点 -> 右子树
后序遍历:左子树 -> 右子树 ->根节点

第五题 : 用两个栈实现队列

题目

用两个栈来实现一个队列,完成队列的PushPop操作。 队列中的元素为int类型。

解析

用一个栈专门来完成push操作;用另一个栈来完成pop操作,如果这个栈为,那么就把第一个栈的元素依次出栈然后入栈到该栈,由于元素在第一个栈中是先入后出,经过这两个步骤,元素就变成了先入先出了,满足队列的性质。

class Solution{
public:
	void push(int node){
		stack1.push(node);
	}
	int pop(){
		// 如果stack2为空,将stack1中元素全部放入stack2
		if (stack2.empty()){
			while(!stack1.empty()){
				stack2.push(stack1.top()), stack1.pop()
			}
		}
		// 输出stack2的top
		int ret = stack2.top();
		stack2.pop();
		return ret;	
	}
private:
	stack<int> stack1;
	stack<int> stack2;
	}

备注

栈 (stack) : 先进后出
队列 (queue): 先进先出

第六题: 旋转数组的最小数字

题目

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{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 l = 0, r = rotateArray.size() - 1;
        while (l < r && rotateArray[l] >= rotateArray[r]) {
            int mid = (l + r) / 2;
            if (rotateArray[l] == rotateArray[r] && rotateArray[l] == rotateArray[mid]) {
                int ret = rotateArray[l];
                for (int i = l + 1; i <= r; ret = min(ret, rotateArray[i++]));
                return ret;
            }
            int mid = (l + r) / 2;
            if (rotateArray[mid] >= rotateArray[l])
                l = mid + 1;
            else
                r = mid;
        }
        return rotateArray[l];
    }
};

参考: 剑指Offer66题之每日6题 - 第一天.

猜你喜欢

转载自blog.csdn.net/muyiyushan/article/details/88344674