代码记录

本文详细介绍了二叉树的前序、中序、后序和层序遍历的递归与非递归实现,并通过力扣(LeetCode)上的经典题目讨论了二叉树的构造及合法二叉搜索树的判断。此外,还探讨了包括两数之和、两数相加和无重复字符最长子串在内的算法问题,分别用不同方法进行了解决,如哈希集合、动态规划等。
摘要由CSDN通过智能技术生成

二叉树

二叉树的前序遍历

题目来源:牛客网==》链接

递归版本

    vector<int> res;
    void helper(TreeNode* root) {
        if (!root) return ;
        res.push_back(root->val);
        helper(root->left);
        helper(root->right);
    }
     
    vector<int> preorderTraversal(TreeNode *root) {
        helper(root);
        return res;
    }

非递归版本(用栈实现)

    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> v;
        if (root!=NULL){
            stack<TreeNode*> s1;
            s1.push(root);
            while(!s1.empty()){
                root=s1.top();
                s1.pop();
                v.push_back(root->val);
                if(root->right!=NULL) s1.push(root->right);
                if(root->left!=NULL) s1.push(root->left);
            }
        }
        return v;
    }

二叉树的中序遍历

题目来源:

递归版本

    vector<int> v;
    vector<int> inorderTraversal(TreeNode *root) {
        helper(root);
        return v;
    }
    void helper(TreeNode *root) {
        if(!root) return;
        helper(root->left);
        v.push_back(root->val);
        helper(root->right);
    }

非递归版本(用栈实现)

    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> s;
        vector<int> v;
        while(!s.empty()||root!=NULL){
            if(root!=NULL){
                s.push(root);
                root=root->left;
            }
            else{
                root=s.top();
                s.pop();
                v.push_back(root->val);
                root=root->right;
            }
        }
        return v;
    }

二叉树的后序遍历

题目来源:

递归版本

    vector<int> v;
    vector<int> postorderTraversal(TreeNode *root) {
        helper(root);
        return v;
    }
    void helper(TreeNode *root) {
        if(!root) return;
        helper(root->left);
        helper(root->right);
        v.push_back(root->val);
    }

非递归版本(用栈实现)

    vector<int> postorderTraversal(TreeNode *root) {
        vector<int> v;
        if (root!=NULL){
            stack<TreeNode*> s1;
            stack<int> s2;
            s1.push(root);
            while(!s1.empty()){
                root=s1.top();
                s1.pop();
                s2.push(root->val);
                if(root->left!=NULL) s1.push(root->left);
                if(root->right!=NULL) s1.push(root->right);
            }
            while(!s2.empty()) {
                v.push_back(s2.top());
                s2.pop();
            }
        }
        return v;
    }

二叉树的层序遍历

题目来源:

用队列实现

    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> ans;
        if (root){
            queue<TreeNode*> que;
            que.push(root);
            while(!que.empty()){
                int n = que.size();
                vector<int> temp;
                for(int i = 0 ;i < n; i++){
                    root = que.front();
                    temp.push_back(root->val);
                    if(root->left)  que.push(root->left);
                    if(root->right) que.push(root->right);  
                    que.pop();             
                }
                ans.push_back(temp);
            }
        }
        return ans;        
    }

dfs版本

    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        dfs(res, root, 0);
        return res;
    }
    void dfs(vector<vector<int>>& res, TreeNode* root, int level) {
        if (!root) return;
        if (level >= res.size())	res.push_back(vector<int>());
        res[level].push_back(root->val);
        dfs(res, root->left, level + 1);
        dfs(res, root->right, level + 1);
    }

从前序与中序遍历序列构造二叉树

题目来源:

用递归实现

    TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
        if(preorder.size()==0) return NULL;
        if(preorder.size()==1) return new TreeNode(preorder[0]);
        else{
            TreeNode *flag=new TreeNode(preorder[0]);
            int t=distance(inorder.begin(),find(inorder.begin(),inorder.end(),preorder[0]));
            vector<int> b(preorder.begin()+1, preorder.begin()+t+1);
            vector<int> c(inorder.begin(), inorder.begin()+t);
            flag->left=buildTree(b,c);
            vector<int> d(preorder.begin()+t+1, preorder.end());
            vector<int> e(inorder.begin()+t+1, inorder.end());
            flag->right=buildTree(d,e);
            return flag;
        }
    }

用栈实现

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if (preorder.empty()) return NULL;
        TreeNode* root = new TreeNode(preorder[0]);
        stack<TreeNode*> stackNode; 
        stackNode.push(root);
        int indexInorder = 0;
        for (int index = 1; index < preorder.size(); index++) {
            TreeNode *curr = stackNode.top();
            if (curr->val != inorder[indexInorder]) {
                curr->left = new TreeNode(preorder[index]); 
                stackNode.push(curr->left);
            }
            else {
                while (!stackNode.empty() && stackNode.top()->val == inorder[indexInorder]) {
                    curr = stackNode.top(); 
                    stackNode.pop();
                    indexInorder++;
                }
                curr->right = new TreeNode(preorder[index]); 
                stackNode.push(curr->right);
            }
        }
        return root;
    }

合法二叉搜索树

题目来源:

递归模版实现

    struct ReturnData{
        bool flag;
        int min_num;
        int max_num;
        ReturnData(bool flag,int min_num,int max_num):flag(flag),min_num(min_num),max_num(max_num){}
    };
    ReturnData f(TreeNode *root){
        if(root->left==NULL && root->right==NULL) return ReturnData(true,root->val,root->val);
        else if(root->left!=NULL && root->right==NULL) {
            ReturnData left=f(root->left);
            if(left.flag&&left.max_num<root->val) return ReturnData(true,left.min_num,root->val);
            else return ReturnData(false,left.min_num,root->val);
        }
        else if(root->left==NULL && root->right!=NULL) {
            ReturnData right=f(root->right);
            if(right.flag&&right.min_num>root->val) return ReturnData(true,root->val,right.max_num);
            else return ReturnData(false,root->val,right.max_num);
        }
        else {
            ReturnData left=f(root->left);
            ReturnData right=f(root->right);
            if(left.flag&&left.max_num<root->val&&right.flag&&right.min_num>root->val)
                return ReturnData(true,left.min_num,right.max_num);
            else return ReturnData(false,left.min_num,right.max_num);
        }
    }
    bool isValidBST(TreeNode *root) {
        if (root==NULL) return true;
        else return f(root).flag;
    }

借助中序遍历

    vector<int> v;
    void inorder(TreeNode* root){
        if(root==NULL)return ;
        inorder(root->left);
        v.push_back(root->val);
        inorder(root->right);
    }
    bool isValidBST(TreeNode* root) {
        if(root==NULL) return true;
        inorder(root);
        for(int i=1;i<v.size();i++){
            if(v[i]<=v[i-1]) return false;
        }
        return true;
    }

力扣leetcode

#1 两数之和

(暴力循环 ,map,最优解) ==》链接
在这里插入图片描述

暴力循环:执行用时:736 ms(defeat11.09%),内存消耗:7.2 MB(defeat100%)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n=nums.size();
        vector<int> res;
        for(int i=0;i<n-1;i++){
            for(int j=i+1;j<n;j++){
                if(nums[i]+nums[j]==target){
                    res.push_back(i);
                    res.push_back(j);
                }
            }
        }
        return res;
    }
};

使用map:执行用时:24 ms(defeat52.7%),内存消耗:8.2 MB(defeat100%)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n=nums.size();
        map<int,int> mp;
        vector<int> res;
        for(int i=0;i<n;i++){
            int t=target-nums[i];
            if(mp.count(t)){
                res.push_back(mp[t]);
                res.push_back(i);
                break;
            }
            else mp[nums[i]]=i;
        }
        return res;
    }
};

网站最优解:执行用时:12 ms(defeat85.62%),内存消耗:8 MB(defeat100%)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> res;
        if(nums.size()<=1)
            return res;
        unordered_map<int,int> myMap;
        for(int i=0;i<nums.size();i++){
            int rest_val=target-nums[i];
            if(myMap.find(rest_val)!=myMap.end()){
                int index=myMap[rest_val];
                if(index==i)
                    continue;
                if(index<i){
                    res.push_back(index);
                    res.push_back(i);
                    return res;
                }else{
                    res.push_back(i);
                    res.push_back(index);
                    return res;
                }
            }
            myMap[nums[i]]=i;
        }
        return res;
    }
};

#2 两数相加

(链表,考虑进位) ==》链接
在这里插入图片描述

链表操作:执行用时:28 ms(defeat69.2%),内存消耗:9.3MB(defeat100%)

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* head=new ListNode(-1);//存放结果的链表
        ListNode* h=head;//移动指针
        int sum=0;//每个位的加和结果
        bool carry=false;//进位标志
        while(l1!=NULL||l2!=NULL){
            sum=0;
            if(l1!=NULL){
                sum+=l1->val;
                l1=l1->next;
            }
            if(l2!=NULL){
                sum+=l2->val;
                l2=l2->next;
            }
            if(carry) sum++;
            h->next=new ListNode(sum%10);
            h=h->next;
            carry=sum>=10?true:false;
        }
        if(carry) h->next=new ListNode(1);
        return head->next;
    }
};

#3 无重复字符的最长子串

(哈希集合 hash set,256字符数组,动态规划) ==》 链接
题目图片

哈希集合 hash set:执行用时:60 ms(defeat27%),内存消耗:11.3MB(defeat39.7%)

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        // 哈希集合,记录每个字符是否出现过
        unordered_set<char> occ;
        int n = s.size();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int rk = -1, ans = 0;
        // 枚举左指针的位置,初始值隐性地表示为 -1
        for (int i = 0; i < n; ++i) {
            if (i != 0) {
                // 左指针向右移动一格,移除一个字符
                occ.erase(s[i - 1]);
            }
            while (rk + 1 < n && !occ.count(s[rk + 1])) {
                // 不断地移动右指针
                occ.insert(s[rk + 1]);
                ++rk;
            }
            // 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = max(ans, rk - i + 1);
        }
        return ans;
    }
};

256字符数组:执行用时:8 ms(defeat93.02%),内存消耗:8.5MB(defeat100%)

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int start = 0, n = s.size();
        vector<int> pos(256, -1);
        int res = 0;
        for(int i = 0; i < n; ++i){
            if(pos[s[i]] >= start) start = pos[s[i]] + 1;
            pos[s[i]] = i;
            res = max(res, i - start + 1);
        }
        return res;
    }
};

动态规划:执行用时:8 ms(defeat93.02%),内存消耗:7.1MB(defeat100%)

动态规划解法解题思路:
状态:
dp[i]表示以第i个字符结尾的无重复字符子串的长度。
比如 abcbc :
dp[0] = 1; “a”
dp[1] = 2; “ab”
dp[2] = 3; “abc”
dp[3] = 2; “cb”
dp[4] = 2; “bc”
初始值:对于第一个字符,dp[0] = 1
状态转移:
对于第i个字符,如果在dp[i-1]所代表的子串中出现,那么从所出现的位置j的下一个位置到i,构成了以i结尾的不重复子串。即dp[i] = i-j;
如果第i个字符不在前面的dp[i-1]子串中出现,那么i-1子串加上i字符构成了i子串,因此 dp[i] = dp[i-1]+1;
那么需要担心j位置后又出现了字符i吗?不需要,因为前面的子串本身就是不重复的,不可能存在两个字符i。
最大值: 返回 max(dp[i]) 即可

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int size = (int)s.size();
        if(size==0){
            return 0;
        }
        int lastLen = 1;
        int max = 1;
        int curLen = 0;
        for(int i=1; i<size; ++i){
            curLen = 0;
            for(int j=i-lastLen; j<=i-1; ++j){
                if(s[j]==s[i]){
                    curLen = i-j;
                    break;
                }
            }
            if(curLen==0){
                curLen = lastLen + 1;
            }
            if(curLen>max){
                max = curLen;
            }
            lastLen = curLen;
        }
        return max;
    }
};

牛客网

算法周周练

用bitset

题目来源:牛客网 ==》 链接
一共有 n个数,第 i 个数是 x i x_i xi x i x_i xi可以取 [ l i l_i li, r i r_i ri] 中任意的一个值。 S = Σ x i 2 S=\Sigma x_i^2 S=Σxi2,求 S 种类数。
输入描述:第一行一个数 n。 然后 n 行,每行两个数表示 l i l_i li, r i r_i ri
输出描述:输出一行一个数表示答案。
备注:1 ≤ n , l i l_i li , r i r_i ri≤ 100。
优质答案 ==》 链接

#pragma GCC optimize(3,"Ofast","inline")    //G++
#include<bits/stdc++.h>
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fcout cout<<setprecision(4)<<fixed
using namespace std;
typedef long long ll;
//======================================
namespace FastIO{
char print_f[105];void read() {}void print() {putchar('\n');}
template <typename T, typename... T2>
inline void read(T &x, T2 &... oth){x = 0;char ch = getchar();ll f = 1;while (!isdigit(ch)){if (ch == '-')f *= -1;ch = getchar();}while (isdigit(ch)){x = x * 10 + ch - 48;ch = getchar();}x *= f;read(oth...);}
template <typename T, typename... T2>
inline void print(T x, T2... oth){ll p3=-1;if(x<0) putchar('-'),x=-x;do{print_f[++p3] = x%10 + 48;}while(x/=10);while(p3>=0) putchar(print_f[p3--]);putchar(' ');print(oth...);}} // namespace FastIO
using FastIO::print;
using FastIO::read;
//======================================
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const int maxn = 1e6+5;
bitset<1000005>pre,ans;
int main() {
#ifndef ONLINE_JUDGE
    freopen("H:\\code\\in.in", "r", stdin);
    freopen("H:\\code\\out.out", "w", stdout);
    clock_t c1 = clock();
#endif
//**************************************
    int n;
    read(n);
    pre[0]=1;
    for(int i=1;i<=n;i++){
        int l,r;
        read(l,r);
        ans.reset();
        for(int i=l;i<=r;i++){
            ans|=pre<<(i*i);
        }
        pre=ans;
    }
    print(ans.count());
//**************************************
     
#ifndef ONLINE_JUDGE
    cerr << "Time:" << clock() - c1 << "ms" << endl;
#endif
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值