剑指Offer刷题-一些水题

一些水题

二叉树中和为某一值的路径

题目描述

输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

思路

【注意】题目对路径的定义:从树的根结点开始往下一直到叶结点
方法一、
map<TreeNode*,int>nodeSum; // 用于记录根节点到这一节点的和
map<TreeNode*,TreeNode*>preNode; // 用于记录节点的父亲节点
当遍历到叶子节点的时候,判断和是否等于给定值,如果等于给定的值,就一直向上寻找父亲,还原路径。
方法二、递归+回溯

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
       // 前序遍历 中序遍历 后序遍历 层序遍历
        stack<TreeNode*> tns;
        TreeNode* r = root;
        vector<vector<int> > res;
        
        map<TreeNode*,int>nodeSum;
        map<TreeNode*,TreeNode*>preNode;
        stack<TreeNode*> trackSta;
        if(r==NULL)return res;
        nodeSum[root] = root->val;
        preNode[root] = NULL;
        while(!tns.empty()||r){
            while(r){
                tns.push(r);
                if(r->left!=NULL){
                    nodeSum[r->left] = r->left->val + nodeSum[r];
                    preNode[r->left] = r;
                }
                if(r->right!=NULL){
                    nodeSum[r->right] = r->right->val + nodeSum[r];
                    preNode[r->right] = r;
                }
                r = r->left;
            }
            if(!tns.empty()){
                r = tns.top();
                tns.pop();
                r = r->right;
            }
        }
        r = root;
        while(r||!tns.empty()){
            while(r){
                tns.push(r);
                // 题目对路径的定义是从根节点到叶子节点!
                if(nodeSum[r]==expectNumber&&r->left==NULL&&r->right==NULL){
                    vector<int> tmp;
                    TreeNode* track = r;
                    while(track){
                        trackSta.push(track);
                        track = preNode[track];
                    }
                    while(!trackSta.empty()){
                        tmp.push_back(trackSta.top()->val);
                        trackSta.pop();
                    }
                    res.push_back(tmp); // 要放进结果集啊
                }
                r = r->left;
            }
            if(!tns.empty()){
                r = tns.top();
                tns.pop();
                r = r->right;
            }
        }
        
        return res;
    }
};

// 方法二、递归+回溯
class Solution {
public:
    using vvi = vector<vector<int>>;
    using vi = vector<int>;
    // 1.root为子树根节点
    // 2.sum为剩余的需要满足的量
    // 3.vi &path 存储路径
    // 4.vvi &ret 存储符合条件的路径
    void dfs(TreeNode *root, int sum, vi &path, vvi &ret) {
        path.push_back(root->val); // 到大当前节点root, path记录
        if (sum == root->val && !root->left && !root->right) {
            ret.push_back(path); // 如果左右节点都为空, 说明到叶子节点, 如果该节点的值能满足剩余量sum, 则该路径path是符合条件的路径, 放入结果集ret
        }
        // 当前节点不是叶子节点的情况如下
        if (root->left) 
        dfs(root->left, sum - root->val, path, ret); // 遍历左子树, 更新需要满足的量sum = sum - root->val, 继续往下走, 把当前的path传递下去
        if (root->right) dfs(root->right, sum - root->val, path, ret);
        path.pop_back(); // 回溯, 当前节点root往下的所有路径都走过了
    }
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        vvi ret;
        vi path;
        if (!root) return ret;
        dfs(root, expectNumber, ans, ret);
        return ret;
    }
};

顺时针打印矩阵

题目描述

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

思路

模拟顺时针行走即可

class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
        vector<int>res;
        // 排除矩阵为空的特殊情况
        if(matrix.size()==0||matrix[0].size()==0)return res;
        vector<vector<int> >vis(matrix.size(), vector<int>(matrix[0].size(), 0));
        int curDir = 0;
        int i=0,j=0;
        //cout<<res.size();
        while(res.size()<matrix.size()*matrix[0].size()){
            while(i>=0&&i<matrix.size()&&j>=0&&j<matrix[0].size()){
                vis[i][j] = 1;
                res.push_back(matrix[i][j]);
                j++;
                // 要注意这里的判断顺序
                if(j>=matrix[0].size())break;
                if(vis[i][j]==1)break;
            }
            // 要注意存完之后及时跳出循环
            if(res.size()>=matrix.size()*matrix[0].size())break;
            j--;
            i++;
            
            while(i>=0&&i<matrix.size()&&j>=0&&j<matrix[0].size()){
                vis[i][j] = 1;
                res.push_back(matrix[i][j]);
                i++;
                // 要注意这里的判断顺序
                if(i>=matrix.size())break;
                if(vis[i][j]==1)break;
            }
            // 要注意存完之后及时跳出循环
            if(res.size()>=matrix.size()*matrix[0].size())break;
            i--;
            j--;
            while(i>=0&&i<matrix.size()&&j>=0&&j<matrix[0].size()){
                vis[i][j] = 1;
                res.push_back(matrix[i][j]);
                j--;
                // 要注意这里的判断顺序
                if(j<0)break;
                if(vis[i][j]==1)break;
            }
            // 要注意存完之后及时跳出循环
            if(res.size()>=matrix.size()*matrix[0].size())break;
            j++;
            i--;
            while(i>=0&&i<matrix.size()&&j>=0&&j<matrix[0].size()){
                vis[i][j] = 1;
                res.push_back(matrix[i][j]);
                i--;
                // 要注意这里的判断顺序
                if(i<0)break;
                if(vis[i][j]==1)break;
            }
            // 要注意存完之后及时跳出循环
            if(res.size()>=matrix.size()*matrix[0].size())break;
            i++;
            j++;
            
        }
        
        return res;
    }
};

替换空格

题目描述

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

注意点

由于没有返回值,是对输入字符串做变换操作,输入字符最后一定要置为’\0’

class Solution {
public:
	void replaceSpace(char *str,int length) {
        string res="";
        for(int i=0;i<length;i++){
            if(str[i]==' '){
                res += "%20";
            }else{
                res.push_back(str[i]);
            }
        }
        for(int i=0;i<res.length();i++){
            str[i] = res[i];
        }
        // 注意点,因为字符数组长度发生变化,结束位置一定要置为'\0'
        str[res.length()] = '\0';
	}
};

二进制中1的个数

题目描述

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

注意点

需要转换成无符号整型

class Solution {
public:
     int  NumberOf1(int n) {
         // 这题注意要先把n转换成无符号整型
         unsigned int m = (unsigned int) n;
         int count=0;
         while(m){
             count += (m&1);
             m>>=1;
         }
         return count;
     }
};

合并两个排序的链表

题目描述

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1==NULL)return pHead2;
        if(pHead2==NULL)return pHead1;
        ListNode* res;
        ListNode* r;
        ListNode* p1 = pHead1;
        ListNode* p2 = pHead2;
        if(pHead1->val<=pHead2->val){
            r = res = pHead1;
            p1 = p1->next;
        }else{
            r = res = pHead2;
            p2 = p2->next;
        }
        while(p1!=NULL&&p2!=NULL){
            if(p1->val<=p2->val){
                r->next = p1;
                r = r->next;
                p1 = p1->next;
            }else{
                r->next = p2;
                r = r->next;
                p2 = p2->next;
            }
        }
        while(p1==NULL&&p2!=NULL){
            r->next = p2;
            r = r->next;
            p2 = p2->next;
        }
        while(p1!=NULL&&p2==NULL){
            r->next = p1;
            r = r->next;
            p1 = p1->next;
        }
        return res;
    }
};

1.构建乘积数组

题目描述:

给定数组A[0,1,…,n-1]
构建数组B[0,1,…,n-1]
B[i]=A[0]×A[1]×A[2]×…×A[i-1]×A[i+1]×A[i+2]×…×A[n-1]
规定:

  1. B[0] = A[1]×A[2]×…×A[n-1]
  2. B[n-1] = A[0]×A[1]×A[2]×…×A[n-2];)
  3. 对于A长度为1的情况,B无意义,故而无法构建,因此该情况不会存在。
  4. 不能使用除法。

思路:

因为不能使用除法,所以选择保存数组A的前缀积和后缀积。

class Solution {
public:
    vector<int> multiply(const vector<int>& A) {
        vector<int>pre_product(1,1);
        vector<int>post_product_temp(1,1);
        vector<int>post_product;
        vector<int>res;
        for(int i=0;i<A.size();i++){
            pre_product.push_back(A[i]*pre_product[i]);
            post_product_temp.push_back(A[A.size()-1-i]*post_product_temp[i]);
        }
        for(int i=post_product_temp.size()-1;i>=1;i--){
            post_product.push_back(post_product_temp[i]);
        }
        for(int i=0;i<A.size();i++){
            if(i==0){
                res.push_back(post_product[1]);
            }else if(i==A.size()-1){
                // 本来是 pre_product[i-1] 前缀积第一个元素是为了方便运算放进去的1 所以要向后移动一个单位  pre_product[i} 
                res.push_back(pre_product[A.size()-1]);
            }else{
                res.push_back(pre_product[i]*post_product[i+1]);
            }
        }
        
        return res;
    }
};

2.字符流中第一个不重复的字符

题目描述:

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。

思路

map计数

猜你喜欢

转载自blog.csdn.net/qq_35903284/article/details/107771964