Day28:搜索与回溯算法

剑指 Offer 37. 序列化二叉树

请实现两个函数,分别用来序列化和反序列化二叉树。

你需要设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

题目分析

1.序列化,需要将null 的叶子节点也加入进来。除了这点的处理,其他的都跟平常的bfs差不多。2.反序列化。主要一些将Str变成vector 形式的int有点麻烦,建立整颗树的方法到挺容易懂

class Codec {
public:
    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        if(root == nullptr) return "[]";
        string res = "[";
        queue<TreeNode*> que;
        que.emplace(root);
        while(!que.empty()) {
            TreeNode* node = que.front();
            que.pop();
            if(node != nullptr) {
                res += (to_string(node->val) + ",");
                que.emplace(node->left);
                que.emplace(node->right);
            }
            else res += "null,";
        }
        res.pop_back();
        res += "]";
        return res;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        if (data == "[]")
            return nullptr;
        vector<string> list = split(data.substr(1, data.length() - 2), ",");
        TreeNode *root = new TreeNode(std::stoi(list[0]));
        queue<TreeNode*> que;
        que.emplace(root);
        int i = 1;
        while(!que.empty()) {
            TreeNode *node = que.front();
            que.pop();
            if(list[i] != "null") {
                node->left = new TreeNode(std::stoi(list[i]));
                que.emplace(node->left);
            }
            i++;
            if(list[i] != "null") {
                node->right = new TreeNode(std::stoi(list[i]));
                que.emplace(node->right);
            }
            i++;
        }
        return root;
    }
    
private:
    // Split a str by a delim
    vector<string> split(string str, string delim) {
        vector<string> list;
        int i = 0, j = 0, len = str.length();
        while (i < len) {
            while (j < len && str[j] != ',')
                j++;
            list.push_back(str.substr(i, j - i));
            i = ++j;
        }
        return list;
    }
};

剑指 Offer 38. 字符串的排列

输入一个字符串,打印出该字符串中字符的所有排列。

题目分析

通过交换来固定某个位置的元素这个思路真的太棒了,就 abc 这个字符串来说,第一个位置可以放 a 或者 b 或者 c,但是如果确定要放某个字符,比如第一个位置放 a,那么第二个位置就只能放 b 或者 c;如果第一个位置放 b,那么第二个位置就只能放 a 或者 c;如果第一个位置放 c,那么第二个位置就只能放 a 或者 b;当把某个字符移动到第一位以后,暂时第一位的字符就固定住了,这时再去确定第二个位置的元素,并且此时第一个位置的元素不会再出现在后面的位置上,依次类推直到确定所有位置的元素,再往前回溯确定每个位置上其他可能出现的元素。注意要在交换后恢复交换,不然可能会丢失一些排列。并在每轮的同级递归中建立了一个set来剪枝。
在这里插入图片描述

class Solution {
public:
    vector<string> permutation(string s) {
        dfs(s, 0);
        return res;
    }
private:
    vector<string> res;
    void dfs(string s, int x) {
        if(x == s.size() - 1) {
            res.push_back(s);                       // 添加排列方案
            return;
        }
        set<int> st;
        for(int i = x; i < s.size(); i++) {
            if(st.find(s[i]) != st.end()) continue; // 重复,因此剪枝
            st.insert(s[i]);
            swap(s[i], s[x]);                       // 交换,将 s[i] 固定在第 x 位
            dfs(s, x + 1);                          // 开启固定第 x + 1 位字符
            swap(s[i], s[x]);                       // 恢复交换
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值