笔试练习day11
目录
- OR63 删除公共字符
- 题目解析
- 代码
- JZ52 两个链表的第一个公共结点
- 题目解析
- 代码
- 方法一
- 方法二
- mari和shiny
- 题目解析
- 代码
感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录
🏀🏀🏀 笔试练习题
OR63 删除公共字符
链接
题目解析
主要这里是删除的字符,其中包含的标点符号,之前我以为只删除字母,导致创建的数组大小为26
这道题用的是哈希,我们通过ASCLL码值与数组下标的对应关系去做
代码
#include <iostream>
using namespace std;
int main() {
string s1,s2;
bool hash[300]={0};
getline(cin,s1);
getline(cin,s2);
for(char ch:s2)hash[ch]=true;
for(auto ch:s1)
{
if(!hash[ch])cout<<ch;
}
return 0;
}
getline函数是因为输入的字符中可能会有空格,我们要将空格读入字符串中,所以要用getline
for(char ch:s2)hash[ch]=true就是通过hash数组下标与ASCLL码值的对应关系,将数组的元素改为true
if(!hash[ch])cout<<ch,因为不是返回字符串,所以我们只需要将s1中没有在s2出现的字符打印出来就行了
JZ52 两个链表的第一个公共结点
链接
题目解析
注意题目描述的是返回传入的pHead1和pHead2的第一个公共结点,所以当他们的后面结点的长度都相当的时候只需要找到一个节点数值相同的就可以返回了
方法一:通过计数的方式
首先我们先遍历一遍链表,将所有的结点个数记下,然后用for循环遍历,for循环的次数为count1-count2的绝对值,因为我们从题目中可以知道,如果有公共结点,那么后面的所有结点都是一样的,且个数也都是一样的,所以在for循环当中我们是不需要判断p1和p2的值是否一样的
当for循环结束后我们就可以用while循环去找公共结点
方法二:方法二是找到他们之间的等量关系
我们假设他们的公共长度为x,其他的长度分别为x1和x2,那么他们会有这样一个关系式
x1+x+x2=x2+x+x1
虽然只是交换了位置,但是我们可以理解成cur1从x1的位置走到他们两个的交点
然后走完公共路程
之后又跳到cur2开始的位置再走
此时我们所走的路程为x1+x,还有x2的路程没有走
同样的cur2走x2的路程到公共交点
然后走完公共路程到cur1的位置
此时所走的路程为x2+x,还有x1的路程没有走
因为他们所走的总路程都是一样的,所以说明他们走完所花的时间也是相同的,那么就说明他们会在走完后相遇,而相遇的位置就是他们的公共交点
也就是说cur1走完后去走cur2,cur2走完后去走cur1,一直这样走直到他们相遇,而此时的位置就是公共交点,没有公共结点的情况也是可以解决的,因为他们走完所以路程是一定会相遇的,如果没有相遇那么就是没有公共结点,所以就返回空
代码
方法一
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
ListNode *p1=pHead1;
ListNode *p2=pHead2;
int count1=0,count2=0;
if(p1==nullptr||p2==nullptr)
return nullptr;
while(p1!=nullptr)
{
count1++;
p1=p1->next;
}
while(p2!=nullptr)
{
count2++;
p2=p2->next;
}
p1=pHead1;
p2=pHead2;
ListNode *ptr=nullptr;
if(count1>count2)
{
for(int i=1;i<=count1-count2;i++)
p1=p1->next;
}
else if(count1<count2)
{
for(int i=1;i<=count2-count1;i++)
p2=p2->next;
}
int count=min(count1,count2);
for(int i=1;i<=count;i++)
{
if(p1->val==p2->val)
{
ptr=p1;
break;
}
else {
ptr=nullptr;
p1=p1->next;
p2=p2->next;
}
}
return ptr;
}
};
方法二
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
ListNode* p1 = pHead1;
ListNode* p2 = pHead2;
while (p1 != p2) {
p1 = (p1 == NULL ? pHead2 : p1->next);
p2 = (p2 == NULL ? pHead1 : p2->next);
}
return p1;
}
};
mari和shiny
链接
题目解析
这道题不可以用排列组合的公式去做,应该需要考虑s h y的先后顺序,当时我以为只需要得到s h y的个数然后相乘就可以得出结果了,结果是错误的
这道题用动态规划去做,并且这是多状态的线性dp
比如我们先固定一个y,然后需要往前找有多少个sh,当y的位置是i的时候,那么要找的就是o到i-1的位置有多少个sh
同样的当i位置为h的时候,我们需要知道o到i-1位置上有多少个s
最后我们还需要推出o-i位置有多少个shy
状态表示如图
状态转移方程推导如下
先说s[i]
s[i]需要分两种情况,当str[i],也就是字符串i位置的字符,当他的字符为s的时候,那么公式就是s[i-1]+1
反之就是s[i-1]
对于h[i],他依然分两种情况
当str[i]为h的时候,我们就需要看他前面有多少个s,此外因为str[i]前面也可能有多个h,而他前面的h有多少个sh是记录在h[i]里面的,所以我们可以得出h[i]=s[i-1]+h[i-1]
如果str[i]不是h的话,那么就只需要考虑他前面有多少个sh就行了,也就是h[i-1]
对于y[i]也是相同的过程,这里就不说了
这里谈谈初始化问题
s[0]看第一个字符是否为s,h[0]因为要组成sh,而开始只有一个字符,所以为0,y[0]和y[1]也都是为0
这道题可以空间优化一下,和之前的滑动窗口方式差不多,用3个变量去解决问题
代码
#include<iostream>
#include<string>
using namespace std;
int n;
string str;
int main()
{cin>>n>>str;
long long s=0,h=0,y=0;
for(int i=0;i<n;i++)
{
char ch=str[i];
if(ch=='s') s++;
else if(ch=='h') h+=s;
else if(ch=='y') y+=h;
}
cout<<y<<endl;
return 0;
}