zoukankan      html  css  js  c++  java
  • 《剑指offer》Q01-12 (牛客10.11)

    T1 二维部分有序数组查找 ☆

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

    由于矩阵部分有序,向上数字递减,向右数字递增:

    1. 目标数字只会出现在行首小于该数的行中
    2. 遍历行i ,若列j 对应的元素大于目标,那么在前 i-1 行,目标只会出现在 j列及以后。

    因此,可以从左下角开始查找。目标比左下角数字小时,上移;当要目标比左下角数字大时,右移。
    搜索的路线是阶梯状,复杂度为O(行数+列数)。

    class Solution {
    public:
        bool Find(int target, vector<vector<int> > array) {
            int nrows = array.size();
            int ncols = array[0].size();
             
            int i = nrows - 1, j = 0;
             
            while(i >= 0 && j < ncols){
                if(array[i][j] == target) return true;
                else if(array[i][j]< target ){
                    j++;
                }else i--;
            }
             
            return false;
        }
    };
    

    WA警告:

    之前的错误代码版本如下,由于判断条件中的 && 写成 , 造成段错误(数组越界访问):

    class Solution {
    public:
        bool Find(int target, vector<vector<int> > array) {
            int nrows = array.size();
            int ncols = array[0].size();
            if( ncols == 0 || nrows == 0) return false;
            for(int i = nrows - 1, j = 0; i >= 0, j < ncols; i--){
                if( array[i][j] == target )
                    return true;
                if( array[i][j] < target){
                    i++;
                    j++;
                }
            }
              
            return false;
        }
    };
    

    T2 字符串字符不等长替换 - 从后往前

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

    实现统计好空格数目从后往前写。问题是 str 所指的空间会内存泄露吧?
    注意补上 ''(应该不会有憨憨如我补了一个' '...

    T3 返回链表的反序 vector

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

    递归或者对正序 vector reverse。

    class Solution {
    public:
        vector<int> printListFromTailToHead(ListNode* head) {
            vector<int> rst;
            if(head == NULL)return rst;
            rst = printListFromTailToHead(head->next);
            rst.emplace_back(head->val);
            return rst;
        }
    };
    
    //----------------------vv---------------------------------
    class Solution {
    public:
        vector<int> printListFromTailToHead(ListNode* head) {
            vector<int> rst;
             
            ListNode* pNode = head;
            while(pNode!=NULL){
                rst.emplace_back(pNode->val);
                pNode=pNode->next;
            }
             
            reverse(rst.begin(),rst.end());
            return rst;
        }
    };
    

    T4 重建二叉树

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

    递归建树。注意递归出口,当有 0 或一个节点时直接返回。

    /**
     * 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) {
            if(pre.size()==0)
                return NULL;
            if(pre.size()==1)
                return new TreeNode(pre[0]);
            TreeNode* root = new TreeNode(pre[0]);
            int lenl =0, lenr = 0,len = vin.size();
            while(lenl<len && vin[lenl]!= pre[0])
                lenl++;
            vector<int> npre,nvin;
            
            npre = vector<int>(pre.begin()+1,pre.begin()+1+lenl);
            nvin = vector<int>(vin.begin(),vin.begin()+lenl);
            root->left = reConstructBinaryTree(npre,nvin);
            
            npre = vector<int>(pre.begin()+1+lenl,pre.end());
            nvin = vector<int>(vin.begin()+lenl+1,vin.end());
            root->right = reConstructBinaryTree(npre,nvin);
            
            return root;
        }
    };
    

    T5 两个栈模拟队列

    用两个栈来实现一个队列,完成队列的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.empty()){
                    int x=stack1.top();
                    stack1.pop();
                    stack2.push(x);
                }
            }
            int x=stack2.top();
            stack2.pop();
            return x;
        }
    
    private:
        stack<int> stack1;
        stack<int> stack2;
    };
    

    T6 旋转数组中的最小元素 - 二分或暴力 ☆

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

    由于旋转后,数组前半段非减,后半段非减,所以从后往前遍历,转折点一定是最小元素。如果没有转折点,那么所有元素都相等。
    ​ . .··
    ​ . ·``

    但是这个转折点可以试着二分。由于转折处的右侧是最小元素,所以选择尽量让区间右端点落在最小元素上。那么:

    1. array[mid] > array[high]
      出现这种情况的array类似[3,4,5,6,0,1,2],此时最小数字一定在mid的右边。
      low = mid + 1
    2. array[mid] == array[high]:
      出现这种情况的array类似 [1,0,1,1,1] 或者[1,1,1,0,1],此时最小数字不好判断在mid左边还是右边,这时只好一步步缩小区间。
      high = high - 1
    3. array[mid] < array[high]:
      出现这种情况的array类似[2,2,3,4,5,6,6],此时最小数字一定就是array[mid]或者在mid的左边。因为右边必然都是递增的。
      high = mid

    注意,考虑最后区间长为2或为3 的情况,上述的收敛方式都会使得 low 和 high 最终都指向最小元素。

    class Solution {
    public:
        int minNumberInRotateArray(vector<int> rotateArray) {
            if(rotateArray.size()==0)
                return 0;
            int lo =0, hi = rotateArray.size()-1,mid;
             
            while(lo< hi){
                mid = lo+((hi-lo)>>1);
                if(rotateArray[mid]>rotateArray[hi])
                    lo=mid+1;
                else if (rotateArray[mid] == rotateArray[hi])
                    hi-=1;
                else hi=mid;
            }
            return rotateArray[hi];
        }
    };
    

    T7 - 10 斐波那契数列 - 递推递归 - 两变量写法

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

    class Solution {
    public:
        int Fibonacci(int n) {
            if(n==0) return 0;
            if(n==1) return 1;
            if(n==2) return 1;
            return Fibonacci(n-1)+Fibonacci(n-2);
        }
    };
    

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

    // 两变量
    class Solution {
    public:
        int jumpFloor(int number) {
            if(number==0)return 1;
            if(number==1)return 1;
            if(number==2)return 2;
            int f=1,g=2;
            number-=2;
            while(number--){
                g=f+g;
                f=g-f;
            }
            return g;
        }
    };
    

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

    // dp
    class Solution {
    public:
        int jumpFloorII(const int number) {
            int** dp=new int*[number+10];
            for(int i=0;i<number+10;i++){
                dp[i]=new int[number+10];
            }
            
            memset(dp,0,sizeof dp);
            
            for(int i=1;i<=number;i++){
                dp[1][i]=1;
            }
            // dp[i][j] 用i步跳上台阶j
            for(int i=2;i<=number;i++){
                for(int j=i;j<=number;j++){
                    for(int k=i-1;k<j;k++){
                        dp[i][j]+=dp[i-1][k];
                    }
                }
            }
            
            int ans=0;
            for(int i=1;i<=number;i++){
                ans+=dp[i][number];  
            }
            return ans;// 返回的变量打错,不可原谅,,
        }
    };
    

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

    类似于前面几题。

    class Solution {
    public:
        int rectCover(int number) {
            if(number==0)    return 0;
            if(number==1)    return 1;
            if(number==2)    return 2;
            int f=1,g=2;
            number-=2;
            while(number--){
                g=f+g;
                f=g-f;
            }
            return g;
        }
    };
    

    T11 二进制中 1 的个数

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

    注意对于负数,右移一位会补 1 而非补零。

    // 1. 去掉符号位 1
    class Solution {
    public:
         int  NumberOf1(int n) {
             int cnt=0;
             if(n<0) {
                 n &=0x7fffffff;
                 cnt++;
             }
            
             while(n){
                 cnt+=(n&1);
                 n>>=1;
             }
             return cnt;
         }
    };
    
    // 2. 转为 unsigned int
    class Solution {
    public:
         int  NumberOf1(int n) {
             unsigned int nn=n;
             int cnt=0;
    
             while(nn){
                 cnt+=(nn&1);
                 nn>>=1;
             }
             return cnt;
         }
    };
    
    // 3. 每次 n&(n-1) 将从右边起的第一个 1 变为 0
    public class Solution {
        public int NumberOf1(int n) {
            int count = 0;
            while(n!= 0){
                count++;
                n = n & (n - 1);
             }
            return count;
        }
    } 
    

    T12 数值的整数次方 - 缜密 - 基数可能为负数

    给定一个double类型的浮点数 base 和 int 类型的整数exponent。求base的exponent次方。 保证base和exponent不同时为0

    class Solution {
    public:
        double Power(double base, int exponent) {
            double ans=1;
            bool neg= false;
            
            else if(exponent<0){
                neg=true;
                exponent=-exponent;
            }
            for( ; exponent; base*=base,exponent/=2){
                if(exponent&1){
                    ans*=base;
                }
            }
            return neg?1/ans:ans;
        }
    };
    
  • 相关阅读:
    SSM环境搭建 原始xml版本
    SpringMVC 学习 十六 中初始化视图解析器过程
    tomcat中http协议的get请求与post请求 是如何携带参数的
    Apache Tomcat 7介绍
    需要补充学习内容
    IIS应用程序池配置详解及优化
    openstack l3路由模式简单理解
    openstack neutron
    openstack网络架构
    linux 统计 TCP 网络连接状态
  • 原文地址:https://www.cnblogs.com/weseewe/p/11675019.html
Copyright © 2011-2022 走看看