剑指offer —— 第2章面试需要的基础知识 面试题 3 - 10

3.二维数组中的查找

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

思路:从右上角开始,不断缩小行数或者列数

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

4.替换空格

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

思路:确定新字符串的长度,从尾到头赋值,避免移动。

class Solution {
public:
	void replaceSpace(char *str,int length) {
            if(str == nullptr || length <= 0)  return;
            int originalLength = 0;
            int numberOfBlank = 0;
            int i = 0;
            while(str[i] != '\0'){
                 ++originalLength;
                if(str[i] == ' '){
                    ++numberOfBlank;
                }
                ++i;
            }
            int newLength = originalLength + numberOfBlank * 2;
            if(newLength > length) return;
            int indexOfOriginal = originalLength;
            int indexOfNew = newLength;                     
            while(indexOfOriginal >= 0 && newLength > originalLength){
                if(str[indexOfOriginal] == ' '){
                    str[indexOfNew--] = '0';
                    str[indexOfNew--] = '2';
                    str[indexOfNew--] = '%';
                }
                else{
                    str[indexOfNew--] = str[indexOfOriginal];
                }
                --indexOfOriginal;
            }
    }
};

5.从尾到头打印链表

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

思路:利用栈结构实现。也可以利用递归,但是要避免栈溢出。

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

6.重建二叉树

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

思路:下面用的LeetCode里的方法,比较后还是书上的方法好,易读、鲁棒,有时间改

/**
 * 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) {
        return create(pre, vin, 0, pre.size() - 1, 0, vin.size() - 1);
    }
private:
    TreeNode* create(vector<int>& preorder, vector<int>& inorder, int ps, int pe, int is, int ie){
        if(ps > pe){
            return nullptr;
        }
        TreeNode* node = new TreeNode(preorder[ps]);
        int pos;
        for(int i = is; i <= ie; i++){
            if(inorder[i] == node->val){
                pos = i;
                break;
            }
        }
        node->left = create(preorder, inorder, ps + 1, ps + pos - is, is, pos - 1);
        node->right = create(preorder, inorder, pe - ie + pos + 1, pe, pos + 1, ie);
        return node;
    }
};

7.用两个栈实现队列

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

思路:第1个负责压入数据,第2个负责输出。当第2个栈为空时将第1个栈的数据全部压入到第2个栈。

class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }

    int pop() {
        if(stack2.size() <= 0){
            while(stack1.size() > 0){
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        //if(stack2.size() == 0)
           //throw new exception("queue is empty");
        int node = stack2.top();
        stack2.pop();
        return node;
    }

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

8.旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

思路:二分查找,LeetCode里要求返回bool类型,这里要求返回值。因为可重复,所以考虑到左右端点与中点值相等的情况,此时只能用顺序查找。

 

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        if(rotateArray.empty()) return 0;
        int index1 = 0;
        int index2 = rotateArray.size() - 1;
        int indexMid = index1;
        while(rotateArray[index1] >= rotateArray[index2]){
            if(index2 == index1 + 1){
                indexMid = index2;
                break;
            }
            indexMid = index1 + (index2 - index1) / 2;
            if(rotateArray[index1] == rotateArray[index2] && 
               rotateArray[index1] == rotateArray[indexMid])
                return minInorder(rotateArray, index1, index2);
                
            if(rotateArray[index1] <= rotateArray[indexMid])
                index1 = indexMid;
           //else if(rotateArray[indexMid] <= rotateArray[index2])
            else
                      index2 = indexMid;
        }
        return rotateArray[indexMid];
    }
private:
    int minInorder(vector<int> rotateArray, int index1, int index2){
        int result = rotateArray[index1];
        for(int i = index1 + 1; i <= index2; i++){
            if(result < rotateArray[i])
                result = rotateArray[i];
        }
        return result;
    }
};

9.斐波那契数列

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。

n<=39

思路: 用递归的话,会重复计算,所以用循环。此外可以根据公式减少循环次数,不过比较麻烦。

跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

思路:其实就是斐波那契数列问题。

class Solution {
public:
    int jumpFloor(int number) {
        int fibOne = 0;
        int fibTwo = 1;
        int fibN;
        if(number == 0) return 0;
        for(int i = 1; i <= number; i++){
            fibN = fibOne + fibTwo;
            fibOne = fibTwo;
            fibTwo = fibN;
        }
        return fibN;
    }
};

变态跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

思路:根据数学归纳法可以得知,跳法共有2^(n-1)种,根据位运算求得。

class Solution {
public:
    int jumpFloorII(int number) {
        int a = 1;
        return a<<(number - 1);
    }
};

矩阵覆盖

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

思路:斐波那契数列问题

class Solution {
public:
    int rectCover(int number) {
        int fib1 = 1;
        int fib2 = 2;
        int fibN = 0;
        if(number == 1 || number == 2) return number;
        
        for(int i = 3; i <= number; i++){
            fibN = fib1 + fib2;
            fib1 = fib2;
            fib2 = fibN;
        }
        return fibN;
    }
};

10.二进制中1的个数

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

思路:如果让该数右移与1做&运算会出现死循环,因为负数右移左边补1。

class Solution {
public:
     int  NumberOf1(int n) {
         unsigned int flag = 1;
         int count = 0;
         while(flag){
             if(n & flag) ++count;
             flag = flag << 1;
         }
         return count;
     }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值