第一题:
因为该函数具有严格的单调性,所以可以二分,即枚举x二分y,但数据范围过小没啥必要。
public class Solution {
public List<List<Integer>> findSolution(CustomFunction func, int z) {
List<List<Integer>> ans=new ArrayList<List<Integer>>();
for(int x=1;x<=1000;x++) {
int l=1;
int r=1000;
int y=-1;
while(l<=r) {
int mid=(l+r)>>1;
if(func.f(x, mid)>=z) {
if(func.f(x, mid)==z) {
y=mid;
break;
}
r=mid-1;
}
else
l=mid+1;
}
if(y==-1)
continue;
ArrayList<Integer> temp=new ArrayList<Integer>();
temp.add(x);
temp.add(y);
ans.add(temp);
}
return ans;
}
}
class CustomFunction {
public int f(int x, int y) {
return 0;
}
}
第二题:
考虑建图,然后找到一个长度为2^n的环。
public class Solution {
public ArrayList<Integer>[] G;
public static boolean find=false;
public List<Integer> circularPermutation(int n, int start) {
G=new ArrayList[1<<n];
for(int i=0;i<G.length;i++)
G[i]=new ArrayList<Integer>();
for(int i=0;i<G.length;i++)
G[i]=new ArrayList<Integer>();
for(int i=0;i<(1<<n);i++) {
for(int j=0;j<n;j++) {
G[i].add(i^(1<<j));
}
}
List<Integer> ans=new ArrayList<Integer>();
boolean[] vis=new boolean[1<<n];
dfs(start,vis,ans,start,n);
return ans;
}
public void dfs(int u,boolean[] vis,List<Integer> ans,int start,int n) {
ans.add(u);
vis[u]=true;
for(int v:G[u]) {
if(v==start&&ans.size()==(1<<n)) {
find=true;
return ;
}
if(vis[v])
continue;
dfs(v,vis,ans,start,n);
if(find)
return ;
}
vis[u]=false;
ans.remove(ans.size()-1);
}
}
第三题:
二进制枚举暴力,感兴趣的可以考虑下01背包能做吗?我觉得没法枚举状态。
public class Solution {
public int maxLength(List<String> arr) {
int n=arr.size();
int ans=0;
for(int i=0;i<(1<<n);i++) {
boolean[] use=new boolean[26];
boolean[] jud=new boolean[26];
int temp=0;
for(int j=0;j<n;j++) {
if((i&(1<<j))!=0) {
boolean flag=true;
Arrays.fill(jud, false);
for(char v:arr.get(j).toCharArray()) {
if(jud[v-'a']) {
flag=false;
break;
}
jud[v-'a']=true;
if(use[v-'a']) {
flag=false;
break;
}
}
if(flag) {
temp+=arr.get(j).length();
for(char v:arr.get(j).toCharArray())
use[v-'a']=true;
}
}
}
ans=Math.max(ans, temp);
}
return ans;
}
}
第四题:
dp[i][j]表示长为i宽为j的矩形最少可有多少个正方形拼接而成。
当i=j时答案肯定为1,当i!=j时考虑以下三种切法:
1.纵向切一刀
2.横向切一刀
3.中间留个正方形,然后枚举中间这个正方形的边延伸出去的情况,需要讨论的东西比较多,但应该是正解。
对于上述的第三种切法,我只枚举了中间的块的大小以及摆放的位置,并没有做其他的讨论,虽然过了,但我觉得应该不是正解。
public class Solution {
public int tilingRectangle(int n, int m) {
int[][] dp=new int[n+1][m+1];
for(int[] temp:dp)
Arrays.fill(temp, Integer.MAX_VALUE/8);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(i==j) {
dp[i][j]=1;
continue;
}
for(int k=1;k<i;k++)
dp[i][j]=Math.min(dp[i][j], dp[k][j]+dp[i-k][j]);
for(int k=1;k<j;k++)
dp[i][j]=Math.min(dp[i][j], dp[i][k]+dp[i][j-k]);
for(int k=1;k<=Math.min(i, j);k++) {
for(int x=1;x+k<=i;x++) {
for(int y=1;y+k<=j;y++) {
dp[i][j]=Math.min(dp[i][j], dp[x][y+k]+dp[x+k][j-y-k]+dp[i-x][y]+dp[i-x-k][j-y]+1);
}
}
}
}
}
return dp[n][m];
}
}