zoukankan      html  css  js  c++  java
  • 【剑指offer】刷题记录3~10

    注:点击题目可直接跳转至leetcode相应的题目代码提交处

    03. 数组中重复的数字

    题目

    找出数组中重复的数字。

    在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

    示例 1:

    输入:
    [2, 3, 1, 0, 2, 5, 3]
    输出:2 或 3

    限制:

    2 <= n <= 100000

    思路

    首先看限制n的范围,发现10万并不算大,所以可以使用哈希,利用下标来计算每个数出现的次数,因为是随意输出一个重复的数字,可以在统计时就看是不是重复了,如果重复了就输出;

    代码

    int a[100001];
    int findRepeatNumber(vector<int>& nums) {
          int n=nums.size();
          for(int i=0;i<n;i++)
          {
              int tmp=nums[i];
              a[tmp]+=1;
              if(a[tmp]>1)
              {
                  return tmp;
              }
          }
          return 0;
    }
    

    04. 二维数组中的查找

    题目

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

    示例:

    现有矩阵 matrix 如下:

    [
    [1, 4, 7, 11, 15],
    [2, 5, 8, 12, 19],
    [3, 6, 9, 16, 22],
    [10, 13, 14, 17, 24],
    [18, 21, 23, 26, 30]
    ]
    给定 target = 5,返回 true。

    思路

    经过评论区提示,可以从右上角看这个矩阵,这样就变成了一个二叉搜索树,然后依次判断即可,注意不要超出矩阵范围。点matrix[i][j]的两个子节点是matrix[i][j-1]matrix[i+1][j]

    代码

    bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
            if(matrix.size()==0||matrix[0].size()==0)
            {
                return false;
            }
            int line=matrix.size();
            int cor=matrix[0].size();
            int i=0;
            int j=cor-1;
            while(i<line&&j>=0)
            {
                if(matrix[i][j]==target)
                {
                    return true;
                }
                else if(target<matrix[i][j])
                {
                    j--;
                }
                else 
                {
                    i++;
                }
            }
            return false;
        }
    

    注意刚开始一定要检查空矩阵的情况,且一定要放在最前面检查,否则力扣会报错:Char 9: runtime error: reference binding to null pointer of type 'std::vector<int, std::allocator<int>>' (stl_vector.h)


    05. 替换空格

    题目

    请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

    示例 1:

    输入:s = "We are happy."
    输出:"We%20are%20happy."

    限制:

    0 <= s 的长度 <= 10000

    思路

    调用C++中固有的关于string类型的函数,详情见:https://www.cnblogs.com/wwj321/p/12381569.html

    代码

    string replaceSpace(string s) {
          int n=s.size();
          string s1="\%20";
          for(int i=0;i<n;i++)
          {
              if(s[i]==' ')
              {
                  s.erase(i,1); 
                  s.insert(i,s1);
                  n=n+2;
                  i=i+2;
              }
          }
          return s;
    }
    

    06. 从尾到头打印链表

    题目

    输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

    示例 1:

    输入:head = [1,3,2]
    输出:[2,3,1]

    限制:

    0 <= 链表长度 <= 10000

    思路

    从反过来可以直接想到用栈。

    代码

    vector<int> reversePrint(ListNode* head) {
            stack<int> S;
            ListNode *h=head;
            while(h!=NULL)
            {
                S.push(h->val);
                h=h->next;
            }
            int num=S.size();
            vector<int> vec(num);
            for(int i=0;i<num;i++)
            {
                vec[i]=S.top();
                S.pop();
            }
            return vec;
    }
    

    07. 重建二叉树

    题目

    输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

    例如,给出

    前序遍历 preorder = [3,9,20,15,7]
    中序遍历 inorder = [9,3,15,20,7]
    

    返回如下的二叉树:

        3
       / 
      9  20
        /  
       15   7
    

    思路

    例如有树:

         A
        /  
       B    C
    

    前序遍历,为ABC,中序遍历为:BAC;可现根据前序遍历找到根节点,然后根据中序遍历分成左右树,再递归左右子树进行建树;

    代码

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
            if(preorder.size()==0)
            {
                return NULL;
            }
            TreeNode* root;
            root =new TreeNode;
            root->left=NULL;
            root->val=preorder[0];
            root->right=NULL;
            int num=preorder.size();     //inorder的size也一样
            vector<int> inleft;
            vector<int> preleft;
            vector<int> preright;
            vector<int> inright;
            for(int i=0;i<num;i++)
            {
                if(i!=0)
                {
                     preleft.push_back(preorder[i]);
                }
                inleft.push_back(inorder[i]);
                if(inorder[i]==preorder[0])
                {
                    for(int j=i+1;j<num;j++)
                    {
                        preright.push_back(preorder[j]);
                        inright.push_back(inorder[j]);
                    }
                    root->left=buildTree(preleft,inleft);
                    root->right=buildTree(preright,inright);
                    return root;
                }
            }
            return root;
        }
    };
    

    我这个是将左右的代码都重新分配到新的数组了。也可以一直用原 有的两个数组,重新写一个递归的函数,将数组下标加入到参数中,这样不用讲原数组移动到新的数组。

    关于treeNode定义,可以这样写:

    TreeNode* root=new TreeNode(preorder[0]);
    

    09. 用两个栈实现队列

    题目

    用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

    示例 1:

    输入:
    ["CQueue","appendTail","deleteHead","deleteHead"]
    [[],[3],[],[]]
    输出:[null,null,3,-1]

    思路

    队列:先进先出;栈:先进后出

    将数据存储在一个栈中,当增加数据时,直接加在栈后面;当删除数据时,将所有数据弹入到另一个栈暂存,然后将栈底的数据删掉,再将暂存的数据弹回来。(有点像汉诺塔)

    代码

    class CQueue {
    public:
        stack<int> S1;
        stack<int> S2;
        CQueue() {
    
        }
        
        void appendTail(int value) {
            S1.push(value);
        }
        
        int deleteHead() {
            if(S1.empty())
            {
                return -1;
            }
            while(!S1.empty())
            {
                int a=S1.top();
                S1.pop();
                S2.push(a);
            }
            int k=S2.top();
            S2.pop();
            while(!S2.empty())
            {
                int b=S2.top();
                S2.pop();
                S1.push(b);
            }
            return k;
        }
    };
    

    10- I. 斐波那契数列

    题目

    写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:

    F(0) = 0, F(1) = 1
    F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
    斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。

    答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

    思路

    递归会比较耗时好空间,斐波那契数列可以直接循环计算,不用递归。

    代码

    class Solution {
    public:
        int fib(int n) {
            if(n==0)
            {
                return 0;
            }
            if(n==1)
            {
                return 1;
            }
            int tmp;
            int a,b;
            a=0;
            b=1;
            for(int i=2;i<=n;i++)
            {
                tmp=a+b;
                if(tmp>1000000007)
                {
                    tmp=tmp-1000000007;   //注:这里原本是取余数运算,因为是一次次加的,
                                          //所以可以改成减法,减法计算速度快很多,
                                          //可以击败100%,如果是取余慢很多
                }
                a=b;
                b=tmp;
            }
            return tmp;
        }
    };
    

    10- II. 青蛙跳台阶问题

    题目

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

    答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

    思路

    最简单的动态规划类题目,可以看作是斐波那契数列;

    代码

    class Solution {
    public:
        int numWays(int n) {
            if(n==0)
            {
                return 1;
            }
            if(n==1)
                return 1;
            if(n==2)
                return 2;
            int a,b;
            a=1;
            b=2;
            int tmp;
            for(int i=3;i<=n;i++)
            {
                tmp=a+b;
                if(tmp>1000000007)
                {
                    tmp=tmp-1000000007;
                }
                a=b;
                b=tmp;
            }
            return tmp;
        }
    };
    

    后续:【剑指offer】刷题记录11~20

  • 相关阅读:
    调研当前大学生的三个痛点
    作业-- 统计文本文件中的字符数、单词数、行数
    我的课程表--项目需求分析
    Android随机生成四则运算
    校友信息管理&SNS互动平台之前言、目录及说明
    校友信息管理&SNS互动平台之技术框架选择
    校友信息管理系统&SNS互动平台之用户需求及概要设计
    WordPress文件上传与下载问题解决
    oc - NSArray基础用法总结
    AutoLayout 使用详细
  • 原文地址:https://www.cnblogs.com/wwj321/p/14519912.html
Copyright © 2011-2022 走看看