23.1.12力扣刷题

起来继续刷题吧
加油QAQ

剑指 Offer 07. 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

按照题解写的
第一种递归的方法
我们通过不断判断左右子树在先序和中序遍历中的范围

class Solution {
    map<int,int>index;
public:
    TreeNode* mybuildTree(vector<int>& preorder, vector<int>& inorder,int preleft,int preright,int inleft,int inright)
    {
        if(preleft>preright)
            return nullptr;
        int inroot=index[preorder[preleft]];//定位中序遍历根节点位置preorder[preleft]得到数字,再用index得到位置下标
        TreeNode* t=new TreeNode(preorder[preleft]);//先序遍历第一个值为根节点
        int size=inroot-inleft;//得到左子树大小
        t->left=mybuildTree(preorder,inorder,preleft+1,preleft+size,inleft,inroot-1);
        t->right=mybuildTree(preorder,inorder,preleft+1+size,preright,inroot+1,inright);
        return t;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n=preorder.size();
        for(int i=0;i<n;i++)
            index[inorder[i]]=i;
        return mybuildTree(preorder,inorder,0,n-1,0,n-1);
    }
};

方法二迭代
写完了差不多明白了但是还是有些一知半解其实QAQ

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(!preorder.size())
            return nullptr;
        stack<TreeNode *>s;
        TreeNode* root=new TreeNode(preorder[0]);//第一个为根节点
        int index=0;
        s.push(root);
        for(int i=1;i<preorder.size();i++)
        {
            TreeNode* t=s.top();
            if(t->val!=inorder[index])
            {
                t->left=new TreeNode(preorder[i]);
                s.push(t->left);
            }
            else
            {
                while(!s.empty()&&s.top()->val==inorder[index])
                {
                    t=s.top();
                    s.pop();
                    index++;
                }
                t->right=new TreeNode(preorder[i]);
                s.push(t->right);
            }
        }
        return root;
    }
};

剑指 Offer 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;
        else if(n==1)
            return 1;
        else
        {
            int a=0,b=1,t;
            n--;
            while(n--)
            {
                t=(b+a)%(1000000007);
                a=b;
                b=t;
            }
            return t;
        }
    }
};

剑指 Offer 10- II. 青蛙跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

没思路。。。难道是组合题?
再想想这题是简单题欸
取模应该可以用快速幂
对了这里
前一个状态和后一个状态有关
可以用递推
斐波那契数列
所以这题和上一题类似?
写一个快速幂吧好久不写了
果然找到规律了
f0=1
f1=1
f2=2
f3=4
f4=5
斐波那契数列

class Solution {
public:
    vector<vector<int>> mul(vector<vector<int>> a,vector<vector<int>> b)
    {
        vector<vector<int>> c{{0,0},{0,0}};
        for(int i=0;i<2;i++)
            for(int j=0;j<2;j++)
            {
                c[i][j] = (int) (((long) a[i][0] * b[0][j] + (long) a[i][1] * b[1][j]) % 1000000007);
            }
        return c;
    }
    int quck(int n)
    {
        vector<vector<int>> a{{1, 1}, {1, 0}};
        vector<vector<int>> ret{{1, 0}, {0, 1}};
        while(n>0)
        {
            if(n&1)
            {
                ret=mul(ret,a);
            }
            n>>=1;
            a=mul(a,a);
        }
        return (ret[1][0]+ret[1][1])%1000000007;
    }
    int numWays(int n) {
        if(n==0)
            return 1;
        else
            return quck(n);
    }
};

剑指 Offer 11. 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一次旋转,该数组的最小值为 1。
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

T~T前几天字节青训营遇到过,天啊我才刚刚理解什么意思,一定是那个青训营题目写的太抽象
其实很简单
我们遍历一下
如果原来单增的
就有a1<a2恒等
我们找到一个a1>a2
那么这个a2肯定是最小值
遍历就ok我写写看

class Solution {
public:
    int minArray(vector<int>& numbers) {
        int n=numbers.size();
        for(int i=0;i<n-1;i++)
        {
            if(numbers[i]>numbers[i+1])
                return numbers[i+1];
        }
        return numbers[0];
    }
};

ok过了
看了其他人写的二分妙呀

写一个二分的吧
可以从51234和34512来思考怎么二分

class Solution {
public:
    int minArray(vector<int>& numbers) {
        int n=numbers.size();
        int left=0,right=n-1;
        while(left<right)
        {
            int mid=(left+right)/2;
            if(numbers[mid]<numbers[left])
                right=mid;
            else if(numbers[mid]>numbers[right])
                left=mid+1;
            else
                right--;
        }
        return numbers[left];
    }
};

剑指 Offer 12. 矩阵中的路径
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。

接下来连续三个中等题欸
加油
初看题有些像动态规划?
想不出来,先写一个简单的搜索吧
还真的是搜索。。。写了一个深搜
广搜写到一半忘记怎么写了,官方解也是搜索。。。。。

class Solution {
public:
    int f=0,len,mp[6][6],n,m;
    void dfs(int x,int y,int step,string word,vector<vector<char>>& board)
    {
        if(step==len)
        {
            f=1;
            return;
        }
        if(step>len)
            return;
        if(x-1>=0&&!mp[x-1][y]&&board[x-1][y]==word[step])
        {
            mp[x-1][y]=1;
            dfs(x-1,y,step+1,word,board);
            mp[x-1][y]=0;
        }
        if(x+1<n&&!mp[x+1][y]&&board[x+1][y]==word[step])
        {
            mp[x+1][y]=1;
            dfs(x+1,y,step+1,word,board);
            mp[x+1][y]=0;
        }
        if(y-1>=0&&!mp[x][y-1]&&board[x][y-1]==word[step])
        {
            mp[x][y-1]=1;
            dfs(x,y-1,step+1,word,board);
            mp[x][y-1]=0;
        }
        if(y+1<m&&!mp[x][y+1]&&board[x][y+1]==word[step])
        {
            mp[x][y+1]=1;
            dfs(x,y+1,step+1,word,board);
            mp[x][y+1]=0;
        }
    }
    bool exist(vector<vector<char>>& board, string word) {
        n=board.size();
        m=board[0].size();
        memset(mp,0,sizeof(mp));
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            {
                if(board[i][j]==word[0])
                {
                    len=word.length();
                    mp[i][j]=1;
                    dfs(i,j,1,word,board);
                    mp[i][j]=0;
                }
            }
        return f;
    }
};

剑指 Offer 14- I. 剪绳子
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

没思路。。感觉是单纯的数学题有个固定的方程
感觉分成2或者3段的时候有最优解?
最优解必须是均分?
n<=58或许我们可以思考一下58时候的最优解
分成三段191920=7220
分成两段2929=841
四段15
151414=44100
猜想?
分成接近10会有最大值
分成五个10一个八的话就是800000
分成8份,七个8+2=4194304
。。。猜想破裂划掉
回到之前的均分有最优解
一共有n/m个
也就是(n/m)^m差不多是这个函数
可以求最大值?单调性?试一下
取对数m=e^(lnn-1)时有最大值

写出来了第一次T~T错了我再写写看

class Solution {
public:
    int cuttingRope(int n) {
        if(n==2)
            return 1;
        int m=int(exp((log(n)/log(2.7))-1)+0.5);//计算分m段时最大
        if(m==1) m=2;
        int a=int((n*1.0/m)+0.5);//这里第一次脑子有些乱写成了0.5
        return pow(a,m-1)*(n-a*(m-1));//还有这里是m-1
    }
};

还是错了T~T只能看解析了
背包。。。动态规划
一开始的思路错了啊
这题真的神奇emmmmm
终于过了

class Solution {
public:
    int cuttingRope(int n) {
        int ans[60]={0};
        ans[1]=1,ans[2]=1;
        for(int i=3;i<=n;i++)
            for(int j=1;j<i-1;j++)
                ans[i]=max(max(j*(i-j),ans[i-j]*j),ans[i]);
        return ans[n];
    }
};

1807. 替换字符串中的括号内容
给你一个字符串 s ,它包含一些括号对,每个括号中包含一个 非空 的键。
比方说,字符串 “(name)is(age)yearsold” 中,有 两个 括号对,分别包含键 “name” 和 “age” 。
你知道许多键对应的值,这些关系由二维字符串数组 knowledge 表示,其中 knowledge[i] = [keyi, valuei] ,表示键 keyi 对应的值为 valuei 。
你需要替换 所有 的括号对。当你替换一个括号对,且它包含的键为 keyi 时,你需要:
将 keyi 和括号用对应的值 valuei 替换。
如果从 knowledge 中无法得知某个键对应的值,你需要将 keyi 和括号用问号 “?” 替换(不需要引号)。
knowledge 中每个键最多只会出现一次。s 中不会有嵌套的括号。
请你返回替换 所有 括号对后的结果字符串。

写一下每日一题
第一次尝试用纯模拟
超时了。。应该是可以稍稍优化的
再看看

class Solution {
public:
    string evaluate(string s, vector<vector<string>>& knowledge) {
        string ans,temp;
        int f=0;//f=1开启替换
        for(int i=0;i<s.length();i++)
        {
            if(f==0&&s[i]=='(')
            {
                temp="";
                f=1;
            } 
            else if(f)
            {
                if(s[i]==')')
                {
                    int f2=1;
                    for(int j=0;j<knowledge.size();j++)
                    {
                        if(temp==knowledge[j][0])
                        {
                            ans+=knowledge[j][1];
                            f2=0;
                            break;
                        }
                    }
                    if(f2)
                        ans+="?";
                    f=0;
                }
                else
                {
                    temp+=s[i];
                }
            }
            else
                ans+=s[i];
        }
        return ans;
    }
};

因为看了给的一个例子
knowledge太多了,线性一个个找超级慢
我们可以用map记录下下表,然后每次查表有无
找到就用下标替换就可以
在这里插入图片描述
时间还是太长。。。不过内存居然是用的差不多最少的
我好奇其他解是空间换时间了吗

class Solution {
public:
    string evaluate(string s, vector<vector<string>>& knowledge) {
        string ans,temp;
        map<string,int>mp;
        int f=0;//f=1开启替换
        for(int j=0;j<knowledge.size();j++)
        {
            mp[knowledge[j][0]]=j+1;
        }
        for(int i=0;i<s.length();i++)
        {
            if(f==0&&s[i]=='(')
            {
                temp="";
                f=1;
            } 
            else if(f)
            {
                if(s[i]==')')
                {
                    if(mp[temp])
                        ans+=knowledge[mp[temp]-1][1];
                    else
                        ans+="?";
                    f=0;
                }
                else
                {
                    temp+=s[i];
                }
            }
            else
                ans+=s[i];
        }
        return ans;
    }
};

!其实和官方解很像,天啊我傻了。。。如果能存下标为什么不直接存替换的字符串,其实这样好些算了继续写吧
看了其他语言真的是八仙过海各显神通

剑指 Offer 24. 反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* p=head,*pre=nullptr,*t;
        while(p)
        {
            t=p;
            p=p->next;
            t->next=pre;
            pre=t;
        }
        return pre;
    }
};

剑指 Offer 35. 复杂链表的复制
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

第一眼看是简单题。。。但是突然发现有好多细节
比如链的顺序,还有数字可以重复
最重要的是random指向的问题
意味着不能一边创建一边random指针指向
所以我们需要将一个链表先创建出来再处理random

yeah!写出来了
链表复杂的是,有时候会用到空指针,还有处理链表的头和尾有些复杂
这题我们可以用map记录下表还有对应节点的指针

class Solution {
public:
    Node* copyRandomList(Node* head) {
        map<Node*,int>mp1;
        map<int,Node*>mp2;
        if(head==NULL)
            return nullptr;
        Node *newhead=new Node(head->val);
        Node *p1,*p2,*pre=newhead;
        int index=2;
        p2=head->next;
        mp1[head]=1;
        mp2[1]=newhead;
        while(p2)
        {
            mp1[p2]=index;
            p1=new Node(p2->val);
            mp2[index]=p1;
            pre->next=p1;
            pre=p1;
            p2=p2->next;
            index++;
        }
        pre->next=NULL;
        //处理random指针
        p2=head;
        p1=newhead;
        while(p2)
        { 
            if(p2->random==NULL)
                p1->random=NULL;
            else
                p1->random=mp2[mp1[p2->random]];
            p2=p2->next;
            p1=p1->next;
        }
        return newhead;
    }
};

看了题解。。。原来可以更简单些用map结点和结点对应
学到了==
还有回溯拷贝真的绝
第一次见回溯的用法学习到了

2283. 判断一个数的数字计数是否等于数位的值
给你一个下标从 0 开始长度为 n 的字符串 num ,它只包含数字。
如果对于 每个 0 <= i < n 的下标 i ,都满足数位 i 在 num 中出现了 num[i]次,那么请你返回 true ,否则返回 false 。

写水题休息一下
遍历即可

class Solution {
public:
    bool digitCount(string num) {
        map<char,int>mp;
        for(char i:num)
            mp[i]++;
        for(int i=0;i<num.length();i++)
            if(mp[char(i+'0')]!=num[i]-'0')
                return 0;
        return 1;
    }
};

剑指 Offer 14- II. 剪绳子 II
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m - 1] 。请问 k[0]k[1]…*k[m - 1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。

2 <= n <= 1000
动态规划背包好像不太方便了
直接使用数学方法然后不断取余就ok

emmm参考题解写的

class Solution {
public:
    int cuttingRope(int n) {
        if(n==2)
            return 1;
        else if(n==3)
            return 2;
        else if(n==4)
            return 4;
        else
        {
            long ans=1;
            while(n>4)
            {
                ans=ans*3%1000000007;
                n-=3;
            }
            return int(ans%1000000007*n%1000000007);
        }
    }
};

剑指 Offer 15. 二进制中1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为 汉明重量).)。

位运算
遍历
移位运算即可

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int ans=0;
        while(n)
        {
            if(n&1)
                ans++;
            n>>=1;
        }
        return ans;
    }
};

剑指 Offer 16. 数值的整数次方
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。不得使用库函数,同时不需要考虑大数问题。

emmm感觉有坑啊,幂次这里有负数
稍稍尝试一下快速幂
负数的话先计算正数的时候最后再计算倒数1/x

class Solution {
public:
    double myPow(double x, int n) {
        int f=0;
        double a=x,ans=1;
        long num=n;//处理-2^31*-1之后越界了。。。我沉默了直接开大
        if(num<0)
        {
            f=1;
            num*=-1;
        }
        while(num)
        {
            if(num&1)
                ans=a*ans;
            a=a*a;
            num>>=1;
        }
        if(f)
            return 1.0/ans;
        else
            return ans;
    }
};

剑指 Offer 17. 打印从1到最大的n位数
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

用logx/log10来判断位数

class Solution {
public:
    vector<int> printNumbers(int n) {
        int i=1;
        vector<int>v;
        while((log(i)/log(10))<=n)
        {
            v.push_back(i);
            i++;
        }
        v.pop_back();
        return v;
    }
};

剑指 Offer 18. 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
注意:此题对比原题有改动

睡前最后一题水题
好困
睡觉了T~T感觉写最后几题的时候脑子不怎么动了

class Solution {
public:
    ListNode* deleteNode(ListNode* head, int val) {
        ListNode *p,*pre;
        if(head->val==val)
            return head->next;
        p=head->next;
        pre=head;
        while(p)
        {
            if(p->val==val)
            {
                pre->next=p->next;
                return head;
            }
            pre=p;
            p=p->next;
        }
        return head;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值