5238. 找出给定方程的正整数解
题目描述
给出一个函数 f(x, y) 和一个目标结果 z,请你计算方程 f(x,y) == z 所有可能的正整数 数对 x 和 y。
给定函数是严格单调的,也就是说:
f(x, y) < f(x + 1, y)
f(x, y) < f(x, y + 1)
函数接口定义如下:
interface CustomFunction {
public:
// Returns positive integer f(x, y) for any given positive integer x and y.
int f(int x, int y);
};
如果你想自定义测试,你可以输入整数 function_id 和一个目标结果 z 作为输入,其中 function_id 表示一个隐藏函数列表中的一个函数编号,题目只会告诉你列表中的 2 个函数。
你可以将满足条件的 结果数对 按任意顺序返回。
示例 1:
输入:function_id = 1, z = 5
输出:[[1,4],[2,3],[3,2],[4,1]]
解释:function_id = 1 表示 f(x, y) = x + y
示例 2:
输入:function_id = 2, z = 5
输出:[[1,5],[5,1]]
解释:function_id = 2 表示 f(x, y) = x * y
提示:
1 <= function_id <= 9
1 <= z <= 100
题目保证 f(x, y) == z 的解处于 1 <= x, y <= 1000 的范围内。
在 1 <= x, y <= 1000 的前提下,题目保证 f(x, y) 是一个 32 位有符号整数。
题解1
首先要理解题意,然后x,y是正整数,最大只能是1000。可能的组合也只有 1000 ∗ 1000 1000 * 1000 1000∗1000种。完全可以用暴力法求解出来。
代码1
/*
* // This is the custom function interface.
* // You should not implement it, or speculate about its implementation
* class CustomFunction {
* public:
* // Returns f(x, y) for any given positive integers x and y.
* // Note that f(x, y) is increasing with respect to both x and y.
* // i.e. f(x, y) < f(x + 1, y), f(x, y) < f(x, y + 1)
* int f(int x, int y);
* };
*/
/*
暴力求解
*/
class Solution {
public:
vector<vector<int>>res;
vector<vector<int>> findSolution(CustomFunction& customfunction, int z) {
for(int i = 1; i <= 1000; ++i){
for(int j = 1; j <= 1000; ++j){
if(customfunction.f(i, j) == z){
res.push_back({i, j});
}
}
}
return res;
}
};
题解2
因为函数是严格单调的,首先代码1,可以加一个break判断,当 c u s t o m f u n c t i o n . f ( i , j ) ≥ z customfunction.f(i, j) \geq z customfunction.f(i,j)≥z时,可以跳出内层循环。
5239. 循环码排列
题目描述
给你两个整数 n 和 start。你的任务是返回任意 (0,1,2,…,2^n-1) 的排列 p,并且满足:
p[0] = start
p[i] 和 p[i+1] 的二进制表示形式只有一位不同
p[0] 和 p[2^n -1] 的二进制表示形式也只有一位不同
示例 1:
输入:n = 2, start = 3
输出:[3,2,0,1]
解释:这个排列的二进制表示是 (11,10,00,01)
所有的相邻元素都有一位是不同的,另一个有效的排列是 [3,1,0,2]
示例 2:
输出:n = 3, start = 2
输出:[2,6,7,5,4,0,1,3]
解释:这个排列的二进制表示是 (010,110,111,101,100,000,001,011)
提示:
1 <= n <= 16
0 <= start < 2^n
题解1
第一反应就是格雷码和自然码。但是忘记转换规则。
变换规则与相关知识,可以参见博客和维基百科
题目中给出的start,相当于是格雷码,先求出对应的自然码,然后逐渐递增。再由自然码,求出格雷码。有了思路很容易写出代码, 这里比赛的时候代码写的很纯朴(fù zá)
代码1
class Solution {
public:
vector<int>res, tmp;
vector<int> circularPermutation(int n, int start) {
//求出起始的自然码
const int MOD = pow(2, n);
//cout << MOD << endl;
res.push_back(start);
int num = start;
for(int i = 0; i < n; ++i){
tmp.push_back(num % 2);
num = num / 2;
}
reverse(tmp.begin(), tmp.end());
num = tmp[0];
for(int i = 1; i < n; ++i){//求start的自然码
tmp[i] = tmp[i] ^ tmp[i - 1];
num = num * 2 + tmp[i];
}
for(int cnt = 0; cnt < MOD - 1; ++cnt){//求格雷码
num = (num + 1) % MOD;
tmp.clear();
int i = num;
for(int j = 0; j < n; ++j){
tmp.push_back(i % 2);
i = i / 2;
}
for(int j = 0; j < n - 1; ++j){
tmp[j] = tmp[j] ^ tmp[j + 1];
}
reverse(tmp.begin(), tmp.end());
int num1 = 0;
for(int j = 0; j < n; ++j){//求出格雷码对应十进数
num1 = num1 * 2 + tmp[j];
}
res.push_back(num1);
}
return res;
}
};
题解2
对代码1进行优化,刚才写法太耿直了,我们可以整点高大上的写法。
自然码转格雷码如公式1。
自
然
码
x
转
格
雷
码
y
:
y
=
x
∧
(
x
>
>
1
)
(1)
自然码x转格雷码y:y = x \wedge (x>>1)\tag{1}
自然码x转格雷码y:y=x∧(x>>1)(1)
格雷码转自然码如以下代码。
/*
x是格雷码
y是自然码(每一位与前面的所有位都异或)
*/
int y = x;
while(x>>=1)
y ^= x;
代码2
class Solution {
public:
vector<int>res, tmp;
vector<int> circularPermutation(int n, int start) {
//求出起始的自然码
const int MOD = pow(2, n);
res.push_back(start);
int num = start;
while(start >>= 1)//求start对应的格雷码
num ^= start;
for(int cnt = 0; cnt < MOD - 1; ++cnt){//自然码+1,求对应的格雷码
num = (num + 1) % MOD;
int num1 = num ^ (num >> 1);
res.push_back(num1);
}
return res;
}
};
题解3
这题也可以用暴力搜索来求解,下一个数字产生只需要将前一个数对应的二进制位修改一个,需要用一个mark来标记已产生的数,保证重复,还需要难证最后一个数和第一个数只相差一个二进制位。
代码3
略,可参照bilibili刀哥讲解。
5240. 串联字符串的最大长度
题目描述
给定一个字符串数组 arr,字符串 s 是将 arr 某一子序列字符串连接所得的字符串,如果 s 中的每一个字符都只出现过一次,那么它就是一个可行解。
请返回所有可行解 s 中最长长度。
示例 1:
输入:arr = [“un”,“iq”,“ue”]
输出:4
解释:所有可能的串联组合是 “”,“un”,“iq”,“ue”,“uniq” 和 “ique”,最大长度为 4。
示例 2:
输入:arr = [“cha”,“r”,“act”,“ers”]
输出:6
解释:可能的解答有 “chaers” 和 “acters”。
示例 3:
输入:arr = [“abcdefghijklmnopqrstuvwxyz”]
输出:26
提示:
1 <= arr.length <= 16
1 <= arr[i].length <= 26
arr[i] 中只含有小写英文字母
题解1
最多只有16个串,其所有的子集也只是 2 16 2^{16} 216。可以用暴力求解,有点类似集合幂集的求法(其实就是),具体见代码。
代码1
class Solution {
public:
bool mark[26];
int maxLength(vector<string>& arr) {
int n = arr.size();
int maxLen = 0;
const int NUM = pow(2, n);
for(int i = 1; i < NUM; ++i){//2 * n - 1种情况
int tmp = i;
memset(mark, false, sizeof(mark));//标记字符是否出现
int cnt = 0;
bool flag = true;
for(int j = 0; j < n; ++j){
if(tmp % 2){//判断对应的二进制位
for(int k = 0; k < arr[j].size(); ++k){
if(!mark[arr[j][k] - 'a']){
mark[arr[j][k] - 'a'] = true;
++cnt;
}
else{
flag = false;
break;
}
}
}
tmp = tmp / 2;
}
if(flag && cnt > maxLen){
maxLen = cnt;
}
}
return maxLen;
}
};
5241. 铺瓷砖
题目描述
你是一位施工队的工长,根据设计师的要求准备为一套设计风格独特的房子进行室内装修。
房子的客厅大小为 n x m,为保持极简的风格,需要使用尽可能少的 正方形 瓷砖来铺盖地面。
假设正方形瓷砖的规格不限,边长都是整数。
请你帮设计师计算一下,最少需要用到多少块方形瓷砖?
示例 1:
输入:n = 2, m = 3
输出:3
解释:3 块地砖就可以铺满卧室。
2 块 1x1 地砖
1 块 2x2 地砖
示例 2:
输入:n = 5, m = 8
输出:5
示例 3:
输入:n = 11, m = 13
输出:6
题解1
没思路,第一名竟然打表,好多人说要举报他。能体会这种心情。
这个题是np问题,所有的多项式解法都有问题,或者说只能是面向数据的解法,数据量增大时,不再适用。
当然这题也可以用暴力求解。参照panpeng代码
代码1
class Solution {
public:
int ans;
int N,M;
vector<vector<int>> Map;
void dfs(int x,int y,int num){
if(x>=N){
ans=min(ans,num);
return;
}
if(num>=ans){
return;
}
int nx=x; ///下一个迭代的位置
int ny=y;
if(ny<M-1){
ny++;
}else{
nx++;
ny=0;
}
if(Map[x][y]==1){
dfs(nx,ny,num);
return;
}
铺砖
int i=y;
for(;i<M;i++){
if(Map[x][i]==1){
break; //不能铺了
}
if(x+i-y>=N){
break; //不能铺了
}
}
int len=i-y;
for(int len=i-y;len>0;len--){
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
Map[x+i][y+j]=1;
}
}
dfs(nx,ny,num+1);
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
Map[x+i][y+j]=0;
}
}
}
}
int tilingRectangle(int n, int m) {
Map=vector<vector<int>>(n,vector<int>(m));
ans=n*m;
N=n;
M=m;
dfs(0,0,0);
return ans;
}
};