leedcode第241场周赛题解
这周的周赛打的很不好,以后还是得多练练,主要是leedcode不熟悉操作(一个类就直接给我整蒙了,,,,最后dp状态转移方程还没想到,差一点点就。。。。)
1.直接dfs搜索一下就好了,每个数都有两种情况(异或和不异或)
2.计算‘0’和‘1’的个数,如果个数相差大于1的话直接就-1了,因为肯定够不成交替序列,之后就直接推两种情况找最小值就行了,别忘了除以2。
3.(看了大佬的代码)对,就是这道题目,前一个操作加数就直接加,后面的操作可以构建个映射,直接去枚举另一个数组就行了,时间复杂度是O(n)。
4.(看了大佬的代码)动态规划标准题,其实只要去找状态转移方程就好了,从n-1到n,考虑(n-1,k)和(n-1,k-1)怎么变化到(n,k)的。
5759. 找出所有子集的异或总和再求和
这道题还是很容易的,只要dfs一下就可以了,只要考虑一下每个数去做不做异或就可以了,最后直接求和就得到答案了。
int ans;
int t;
int sum;
bool pan[20];
class Solution {
public:
void dfs(int a,vector<int>& nums)
{
if(a==t)
{
ans+=sum;
}
else
{
dfs(a+1,nums);
pan[a]=true;
int q=sum;
sum=sum^nums[a];
dfs(a+1,nums);
pan[a]=false;
sum=q;
}
}
int subsetXORSum(vector<int>& nums) {
ans=0;
sum=0;
t=nums.size();
memset(pan,0,sizeof(pan));
dfs(0,nums);
return ans;
}
};
5760. 构成交替字符串需要的最小交换次数
这道题主要是看着复杂,仔细想想其实很简单。
1.首先,你需要考虑字符串中‘0’和‘1’的个数,如果个数相差大于1的话,肯定够不成交替的01字符串(这个应该很好想吧),所以此时只需要返回-1就行了。
2.之后,能够完成01交替字符串的,目标状态只有两种,一种是0101010…,另一种是1010101010…,所以现在只要考虑找到变成这两种状态的步数的最小值就是答案啦。
3.第一种情况和第二种情况的思想其实是一样的,只要看奇数位置或者偶数位置的字符是不是‘0‘或者’1’就行了,如果不是的话就令改变次数加1就行了。
4.最后的话,因为规定的操作是交换字符而不是直接改字符,所以再使操作数除以2(如果此时世是奇数除以2的话,直接取另外一个,不需要考虑别的,因为奇数不能完成交换字符操作),最后最小的就是答案了。
class Solution {
public:
int minSwaps(string s) {
int ans=0;
int nums0=0;
int nums1=0;
int len=s.length();
for(int i=0;i<len;i++)
{
if(s[i]=='0')
{
nums0++;
}
else
{
nums1++;
}
}
if(abs(nums0-nums1)<=1)
{
int ans1=0;int ans2=0;
for(int i=0;i<len;i++)
{
if(i%2==0)
{
if(s[i]!='1')
{
ans1++;
}
}
else
{
if(s[i]!='0')
{
ans1++;
}
}
}
for(int i=0;i<len;i++)
{
if(i%2==1)
{
if(s[i]!='1')
{
ans2++;
}
}
else
{
if(s[i]!='0')
{
ans2++;
}
}
}
//cout<<ans1<<" "<<ans2<<endl;
if(ans1%2!=0||ans2%2!=0)
{
if(ans1%2!=0)
{
ans=ans2/2;
}
else if(ans2%2!=0)
{
ans=ans1/2;
}
}
else
{
ans1=ans1/2;
ans2=ans2/2;
ans=min(ans1,ans2);
}
}
else
{
ans=-1;
}
return ans;
}
};
5761. 找出和为指定值的下标对
这题目主要是遇到类别蒙(泪目!!!!),第一个操作就直接加就完事了,第二个操作需要构建一个映射,使得直接去枚举另一个数组就可以了,将时间复杂度降到O(n)。
class FindSumPairs {
public:
int a[200005], b[200005];
int n, m;
map<int, int> hsh;
FindSumPairs(vector<int>& nums1, vector<int>& nums2) {
n = nums1.size(), m = nums2.size();
hsh.clear();
for (int i = 0; i < m; i ++) {
hsh[nums2[i]] ++;
}
for (int i = 0; i < n; i ++) a[i + 1] = nums1[i];
for (int i = 0; i < m; i ++) b[i + 1] = nums2[i];
}
void add(int index, int val) {
hsh[b[index + 1]] --;
b[index + 1] += val;
hsh[b[index + 1]] ++;
}
int count(int tot) {
int ans = 0;
for (int i = 1; i <= n; i ++) ans += hsh[tot - a[i]];
return ans;
}
};
/**
* Your FindSumPairs object will be instantiated and called as such:
* FindSumPairs* obj = new FindSumPairs(nums1, nums2);
* obj->add(index,val);
* int param_2 = obj->count(tot);
*/
5762. 恰有 K 根木棍可以看到的排列数目
这就是一道常规动态规划题目,只要去构造状态转移方程就可以了,其实从n-1加上一个数到n是怎么变化的
1.n-1->n,添加的这个数要比所有数大,如果此时从(n-1,k)->(n,k)这个变化考虑的话,其实就是用n去替换变换前的n-1,之后在考虑前面构成的子序列的变化,因为前面有n-1个数,还有一个数可以替换,所以共有n-1种替换方法。
2.n-1->n,添加的这个数要比所有数大,如果此时从(n-1,k-1)->(n,k)这个变化考虑的话,那么这个数只要填到变化前的数列n-1的后面就可以了,只有1种替换方法。
综上,(n,k)=(n-1)*(n-1,k)+(n-1,k-1).
接着就是dp起来,,,,,,,,,,
class Solution {
public:
bool vis[1005][1005];
int f[1005][1005];
const int mod = (int )1e9 + 7;
int dp(int n, int k) {
if (n == 0 && k == 0) return 1;
if (k == 0) return 0;
if (n == 0) return 0;
if (vis[n][k]) return f[n][k];
vis[n][k] = true;
return f[n][k] = (1LL * (n - 1) * dp(n - 1, k) + dp(n - 1, k - 1)) % mod;
}
int rearrangeSticks(int n, int k) {
return dp(n, k);
}
};
本人很菜,不要喷我,呜呜呜呜…,自己的水平还是太低,常规的动态规划题目反应太慢了,状态转移方程推不出来,并且常规的空间换时间的思想还是用的不太好。继续加油!!!!!