剑指offer(待更新)

注:所有题目来源于leetcode官网

  1. 剑指offer-03.数组中重复的数组
    难度:简单
    题目:找出数组中重复的数字。在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
    方法一:
//用一个map,记录所有数字出现的个数,然后遍历map,找到个数第一次大于1的数字。
class Solution {
private:
    unordered_map<int,int> mp;
public:
    int findRepeatNumber(vector<int>& nums) {
        if(nums.size() == 0) return 0;
        for(int i=0;i<nums.size();i++)
        {
            if(mp.find(nums[i]) == mp.end())
            {
                pair<int,int> pr(nums[i],1);
                mp.insert(pr);
            }
            else
            {
                mp[nums[i]]++;
            }
        }
        unordered_map<int,int>::iterator ite = mp.begin();
        int nMax = 0;
        int num;
        while(ite != mp.end())
        {
            if(ite->second > nMax)
            {
                num = ite->first;
                nMax = ite->second;
            }   
            ite++;
        }
        return num;
    }
};

方法二:

//遍历一遍数组即可,因为数字范围刚好是下标范围,根据这个特点。
//看每个数组里元素里的值,把它代表的下标里的元素进行对比,如果不相等,调换位置;若相等,说明找到重复得了,直接返回即可。O(n)
class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int nSize = nums.size();
        for(int i=0;i<nSize;i++)
        {
            if(i == nums[i]) continue;//这里指的注意,不判断的话,即使出现一次也会返回。
            if(nums[i] == nums[nums[i]])
            {
                return nums[i];
            }
            else
            {
                nums[i] = nums[i] ^ nums[nums[i]];
                nums[nums[i]] =  nums[i] ^ nums[nums[i]];
                nums[i] = nums[i] ^ nums[nums[i]];
            }
        }
        return -1;
    }
};
  1. 剑指offer-66.构建乘积数组
    难度:简单
    题目:给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B 中的元素 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。
    代码:
//第一次遍历,从前往后,每个元素前半部分的乘积值为:前一个的左乘积,再乘以前一个的元素的值即可。
//第二次遍历,从后往前,每个元素后半部分的乘积值为:后一个的右乘积值,再乘以后一个的元素值即可。
//两个数组乘积即最后结果。
class Solution {
public:
    vector<int> constructArr(vector<int>& a) {
        int nSize = a.size();
        vector<int> leftvec(nSize,1);
        vector<int> rightvec(nSize,1);
        for(int i=0;i<nSize;i++)
        {
            if(i==0) continue;
            leftvec[i] = leftvec[i-1]*a[i-1];
        }
        for(int i=nSize-1;i>=0;i--)
        {
            if(i==nSize-1) continue;
            rightvec[i] = rightvec[i+1]*a[i+1];
        }
        for(int i=0;i<nSize;i++)
        {
            leftvec[i] = leftvec[i]*rightvec[i];
        }
        return leftvec;
    }
};
  1. 剑指offer-20.表示数值的字符串
    难度:中等
    题目:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、“5e2”、"-123"、“3.1416”、"-1E-16"、“0123"都表示数值,但"12e”、“1a3.14”、“1.2.3”、"±5"及"12e+5.4"都不是。
    代码:
//1.判断是否有符号,即'+'和'-',要么没有要么只能有一个,并且一定是第一个
//2.从第一个非符号数开始判断,一直往后看,直到\0。如果遇到E/e,不能遇到.
//3.小数点最多只能有一个。
//4.e/E和后面的数字,要么都有,要么都没有,也就是说e/E不能结尾,后面的数字可有符号
//leetcode的测试用例有的有点无语,按着用例改了好久....
class Solution {
public:
    bool isNumber(string s) {
        int nSize = s.size();
       if(nSize == 0) return false;
       //注:如果前面和后面有空格,排除
       int j=0;
        while(j<nSize && s[j]==' ')
            j++;
        int k=nSize-1;
        while(k>=0 && s[k]==' ')
            k--;
        s = s.substr(j,k-j+1);
        //去掉符号位
         if(s[0] == '+' || s[0]=='-')
            s = s.substr(1,nSize-1);
        //开始匹配剩下的
        int flag1 = 0;//e/E是否出现
        int flag2 = 0;//小数点是否出现
        int i;
        nSize = s.size();
        if(nSize == 0) return false;
        //'.'可以开头或结尾,但是不能单独存在
        if(0==nSize-1 && s[i]=='.') return false;
        for(i=0;i<nSize;i++)
        {
            if(s[i] == '.')//2.小数点
            {
                //if(i==0 || i==nSize-1) break;
                if(flag1==1 || flag2==1) break;
                flag2 = 1;
            }
            else if(s[i]=='E' || s[i]=='e')
            {
                if(flag1 == 1) break;//  || flag2==1
                if(i==0 || i == nSize-1) break;
                if(s[i+1] == '.') break;//e后面不能接'.'
                if(i == 1 && s[0] == '.') break;
                if(s[i+1]=='+' || s[i+1]=='-')
                {
                    if(i+2==nSize) return false;//如果出现运算符,后面必须加数字。
                    i++;
                }
                flag1 = 1;
            }
            else if(s[i]-'0'>=0 && s[i]-'0'<=9)
            {
                continue;
            }
            else
                break;
        }
        if(i >= nSize) return true;
        return false;
    }
};
  1. 剑指offer-50.第一个只出现一次的字符
    难度:简单
    题目:在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
    代码:
//创建字符容器;
//第一次遍历,记录每个字符的个数。
//第二次遍历,找到第一个出现个数为1的字符,返回即可。
class Solution {
public:
    char firstUniqChar(string s) {
        int nSize = s.size();
        unordered_map<char,int> mp;
        for(int i=0;i<nSize;i++)
        {
            mp[s[i]]++;
        }
        for(int i=0;i<nSize;i++)
            if(mp[s[i]] == 1)
                return s[i];
        return ' ';
    }
};
  1. 剑指offer-12.矩阵中的路径
    题型:回溯、递归
    难度:中等
    题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
    [[“a”,“b”,“c”,“e”],
    [“s”,“f”,“c”,“s”],
    [“a”,“d”,“e”,“e”]]
    但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
    代码:
class Solution {
public:
    bool FindPath(vector<vector<char>>& board, string word,int index,int x,int y,int maxx,int maxy){
        if(x>=maxx || y>=maxy || x<0 || y<0 || board[x][y]!=word[index])
            return false;
        if(index == word.size()-1) return true;
        //把当前已经用过的字符记录为特殊标记'*',但记得标记上一次的
        char temp = board[x][y];
        board[x][y] = '*';
        //每一步可以在矩阵中向左、右、上、下移动一格
        bool res = ( FindPath(board,word,index+1,x-1,y,maxx,maxy)||
                   FindPath(board,word,index+1,x+1,y,maxx,maxy)||
                   FindPath(board,word,index+1,x,y-1,maxx,maxy)||
                   FindPath(board,word,index+1,x,y+1,maxx,maxy) );
        //把原数组归位,因为此时的结果只是从当前位置出发。
        board[x][y] = temp;
        return res;
    }
    bool exist(vector<vector<char>>& board, string word) {
        if(board.size() == 0) return false;
        int maxx = board.size();
        int maxy = board[0].size();
        //从每一个节点出发,去看是否存在满足条件的路径
        for(int i=0;i<maxx;i++)
            for(int j=0;j<maxy;j++)
                if(FindPath(board,word,0,i,j,maxx,maxy) )
                    return true;

        return false;

    }
};
  1. 剑指offer49-丑数
    难度:中等
    题目:我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
    代码:
class Solution {
public:
    int nthUglyNumber(int n) {
        if(n==0 ) return 0;
        int p2=0,p3=0,p5=0;
        vector<int> vec(n,0);
        vec[0] = 1;
        for(int i=1;i<n;i++)
        {
            int nMin;
            nMin = vec[p2]*2;
            if(nMin > vec[p3]*3)
                nMin = vec[p3]*3;
            if(nMin > vec[p5]*5)
                nMin = vec[p5]*5;
            if(nMin == vec[p2]*2)
            {
                vec[i] = nMin;
                p2++;
            }
            if(nMin == vec[p3]*3)
            {
                vec[i] = nMin;
                p3++;
            }
            if(nMin == vec[p5]*5)
            {
                vec[i] = nMin;
                p5++;
            }
        }
        return vec[n-1];
    }
};
  1. 剑指offer-68(1)-二叉搜索树的最近公共祖先
    题型:树,递归
    难度:简单
    题目:给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
    代码:
/**
 * 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* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == nullptr) return nullptr; 
        if(p == nullptr) return q;
        if(q==nullptr || p==q) return p;
        if(root==p || root==q) return root;
        if(root->val>p->val && root->val<q->val)
            return root;
        if(root->val<p->val && root->val>q->val)
            return root;
        if(root->val>p->val && root->val>q->val)
        {
            return lowestCommonAncestor(root->left,p,q);
        }
        if(root->val<p->val && root->val<q->val)
            return lowestCommonAncestor(root->right,p,q);
        return nullptr;
    }
};
  1. 剑指offer-68(2)-二叉树的最近公共祖先
    题型:树、递归
    题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
    代码:
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
 //与BST寻找公共祖先不同的是,这棵树无序,分别找最左和最右,直到找到这个节点或一边为nullptr结束
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root==nullptr || p==nullptr || q==nullptr) return nullptr;
        if(root==p || root==q) return root;
        TreeNode *pLeft = lowestCommonAncestor(root->left,p,q);
        TreeNode *pRight = lowestCommonAncestor(root->right,p,q);
        if(pLeft == nullptr) return pRight;
        if(pRight == nullptr) return pLeft;
        return root;
    }
};
  1. 剑指offer-18删除链表的节点
    题型:链表
    难度:简单
    题目:给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。
    代码:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* deleteNode(ListNode* head, int val) {
        if(head == nullptr) return head;
        if(head->val == val) return head->next;
        head->next = deleteNode(head->next,val);
        return head;
    }
};
  1. 剑指offer-10青蛙跳台阶问题
    题型:动规、递归
    难度:简单
    题目:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
    答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
    代码:
//递归做会超时
class Solution {
public:
    int numWays(int n) {
        if(n==0) return 1;
        if(n <= 2) return n;
        int n1=1,n2=2;
        for(int i=3;i<=n;i++)
        {
            int temp = n2;
            n2 =  n1%1000000007+n2%1000000007;
            n1 = temp;
        }
        return n2%1000000007;
    }
};
  1. 剑指 Offer 11. 旋转数组的最小数字
    题型:数组、二分
    难度:简单
    题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
    代码:
class Solution {
public:
    int minArray(vector<int>& numbers) {
        int n = numbers.size();
        if(n == 0) return -1;
        int low = 0,high = n-1;
        int mid = low;
        while(low < high)
        {
            if(numbers[low] < numbers[high]) return numbers[low];
            mid = low+(high-low)/2;
            if(numbers[low] > numbers[mid])
            {
                high = mid;
                low++;
            }
            else if(numbers[mid] > numbers[high])
            {
                low = mid+1;
            }
            else
            {
                low++;
            }
        }
        return numbers[low];
    }
};
  1. 剑指 Offer 26. 树的子结构
    题型:递归、树
    难度:中等
    题目:输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
    B是A的子结构, 即 A中有出现和B相同的结构和节点值。
    代码:
/**
 * 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:
    bool dfs(TreeNode* A, TreeNode* B){
        if(B == nullptr) return true;
        if(A == nullptr) return false;
        if(A->val == B->val)
        {
            return dfs(A->left,B->left)&&dfs(A->right,B->right);
        }
        else
            return false;
    }
    bool isSubStructure(TreeNode* A, TreeNode* B) {
        if(A==nullptr || B==nullptr) return false;
        return dfs(A,B)||isSubStructure(A->left,B)||isSubStructure(A->right,B);
    }
};

13.剑指offer-32-1从上到下打印二叉树1
题型:树、 广优
难度:中等
题目:从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
代码:

/**
 * 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:
    vector<int> levelOrder(TreeNode* root) {
        vector<int> vec;
        if(root == nullptr) return vec;
        queue<TreeNode *> que;
        que.push(root);
        while(!que.empty())
        {
            TreeNode *pTemp = que.front();
            que.pop();
            vec.push_back(pTemp->val);
            if(pTemp->left)
                que.push(pTemp->left);
            if(pTemp->right)
                que.push(pTemp->right);
        }
        return vec;
    }
};
  1. 剑指offer-32-2从上到下打印二叉树2
    题型:树
    难度:简单
    题目:从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。
    代码:
/**
 * 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:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int> > vec;
        if(root == nullptr) return vec;
        queue<TreeNode *> que;
        vector<int> tempvec;
        que.push(root);
        while(!que.empty())
        {
            int len = que.size();
            for(int i=0;i<len;i++)
            {
                TreeNode *pTemp = que.front();
                que.pop();
                tempvec.push_back(pTemp->val);
                if(pTemp->left)
                    que.push(pTemp->left);
                if(pTemp->right)
                    que.push(pTemp->right);
            }
            vec.push_back(tempvec);
            tempvec.clear();
        }
        return vec;

    }
};
  1. 剑指offer32-3-从上到下打印二叉树3
    题型:树
    难度:中等
    题目:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
    代码:
/**
 * 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:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int> > vec;
        if(root == nullptr) return vec;
        deque<TreeNode *> que1;//头出
        deque<TreeNode *> que2;//尾出
        que1.push_back(root);
        vector<int> tempvec;
        while(!que1.empty())
        {
            int len = que1.size();
            //第一次是奇数行,处理、放左、放右
            for(int i=0;i<len;i++)
            {
                TreeNode *pTemp = que1.front();
                que1.pop_front();
                tempvec.push_back(pTemp->val);
                if(pTemp->left)
                    que2.push_back(pTemp->left);
                if(pTemp->right)
                    que2.push_back(pTemp->right);
            }
            //把奇数行放到大数组里
            if(tempvec.size() > 0)
                vec.push_back(tempvec);
            tempvec.clear();
            //下一次是偶数行,把刚才装进队列里的节点,从后往前处理
            while(!que2.empty())
            {
                int len = que2.size();
                for(int i=0;i<len;i++)
                {
                    TreeNode *pTemp = que2.back();
                    que2.pop_back();
                    tempvec.push_back(pTemp->val);
                    if(pTemp->right)
                        que1.push_front(pTemp->right);
                    if(pTemp->left)
                        que1.push_front(pTemp->left);
                }
            }
            if(tempvec.size() > 0)
                vec.push_back(tempvec);
            tempvec.clear();
        }
        return vec;
    }
};
  1. 剑指offer55-1-二叉树的深度
    题型:树
    难度:简单
    题目:输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
    代码:
    (1)递归法
/**
 * 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:
    int maxDepth(TreeNode* root) {
        if(root == nullptr) return 0;
        int llen = maxDepth(root->left)+1;
        int rlen = maxDepth(root->right)+1;
        return llen>rlen?llen:rlen;
    }
};

(2)非递归法

/**
 * 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:
    int maxDepth(TreeNode* root) {
        if(root == nullptr) return 0;
        queue<TreeNode *> sk;
        sk.push(root);
        int res = 0;
        while(!sk.empty())
        {
            int len = sk.size();
            while(len > 0)
            {
                TreeNode *pTemp = sk.front();
                sk.pop();
                if(pTemp->left)
                    sk.push(pTemp->left);
                if(pTemp->right)
                    sk.push(pTemp->right);
                len--;
            }
            res++;
        }
        return res;
    }
};                     
  1. 剑指offer-24-反转链表
    题型:链表
    难度:简单
    题目:定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr) return nullptr;
        ListNode *pNewHead = nullptr;
        ListNode *p1 = head;
        ListNode *p2 = head->next;
        while(p1 && p2)
        {
            p1->next = pNewHead;
            pNewHead = p1;
            p1 = p2;
            p2 = p2->next;
        }
        if(p1)
            p1->next = pNewHead;
        return p1;
    }
};
  1. 剑指offer-48-最长不含重复子串
    题型:双指针
    难度:中等
    题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
    代码:
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int n = s.size();
        if(n == 0) return 0;
        int left=0;
        unordered_map<char,int> mp;
        int res =1;
        mp[s[0]]++;
        for(int i=1;i<n;i++)
        {
            mp[s[i]]++;
            while(mp[s[i]] > 1)
            {
                mp[s[left]]--;
                left++;
            }
            if(i-left+1 > res)
                res = i-left+1;
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值