1979. 找出数组的最大公约数
这次的第三题做出来还是挺开心的。
第四题是真的没啥思路,发呆差不多40分钟。。。
后面补的时候也觉得,第四题的难度很大。
题目描述
给你一个整数数组
nums
,返回数组中最大数和最小数的最大公约数。
两个数的最大公约数是能够被两个数整除的最大正整数。
解题思路
简单的gcd
class Solution {
public int findGCD(int[] nums) {
int Min = Integer.MAX_VALUE;
int Max = Integer.MIN_VALUE;
for(int n:nums) {
Min = Math.min(n, Min);
Max = Math.max(n, Max);
}
return GCD(Min,Max);
}
private int GCD(int min, int max) {
int a = Math.max(max, min);
int b = Math.min(max, min);
if(b==0) {
return a;
}
return GCD(a%b,b);
}
}
5851. 找出不同的二进制字符串
题目描述
给你一个字符串数组
nums
,该数组由n
个互不相同的二进制字符串组成,且每个字符串长度都是n
。请你找出并返回一个长度为n
且没有出现在nums
中的二进制字符串。如果存在多种答案,只需返回任意一个即可。
示例 1:
输入: nums = [“01”,“10”]
输出:“11”
解释:“11” 没有出现在 nums 中。“00” 也是正确答案。
示例 2:
输入: nums = [“00”,“01”]
输出:“11”
解释:“11” 没有出现在 nums 中。“10” 也是正确答案。
提示:
n == nums.length
1 <= n <= 16
nums[i].length == n
nums[i] 为 '0' 或 '1'
解题思路
这题我是真的服了,简单的思路就是生成一个数组记录对应数字是否已经被记录,之后再返回第一个未被访问的数字。
class Solution {
public String findDifferentBinaryString(String[] nums) {
boolean[] visited = new boolean[(int) Math.pow(2, nums.length)];
for(String s:nums) {
long ans = StringToNum(s);
visited[(int) ans] = true;
}
for(int i=0;i<visited.length;i++) {
if(!visited[i]) {
StringBuffer ans = new StringBuffer();
int temp = i;
while(temp>0) {
if(temp%2==1) {
ans.append('1');
}else {
ans.append('0');
}
temp>>=1;
}
int t = nums.length-ans.length();
String pre = "";
while(t>0) {
pre+=0;
t--;
}
return pre + ans.reverse();
}
}
return "";
}
private long StringToNum(String s) {
int i=0;
int ans = 0;
while(i<s.length()) {
if(s.charAt(i)=='1') {
ans = ans*2+1;
}else
ans = ans*2;
i++;
}
return ans;
}
}
赛后看到大佬写的,服了。想过有简单的方法没想到这么简单。
class Solution {
public:
string findDifferentBinaryString(vector<string>& a) {
int n= a.size();
string s;
for (int i = 0; i < n; ++i)
s.push_back(a[i][i] ^ 1);
return s;
}
};
1981. 最小化目标值与所选元素的差
题目描述
给你一个大小为
m x n
的整数矩阵mat
和一个整数target
。
从矩阵的每一行中选择一个整数,你的目标是最小化所有选中元素之和与目标值target
的绝对差 。
返回最小的绝对差。
a
和b
两数字的绝对差是a - b
的绝对值。
示例1:
输入: mat = [[1,2,3],[4,5,6],[7,8,9]], target = 13
输出: 0
解释: 一种可能的最优选择方案是:
- 第一行选出 1
- 第二行选出 5
- 第三行选出 7
所选元素的和是 13 ,等于目标值,所以绝对差是 0 。
提示:
-m == mat.length
-n == mat[i].length
-1 <= m, n <= 70
-1 <= mat[i][j] <= 70
-1 <= target <= 800
解题思路
本题第一想法就是动态规划。
怎么设置dp和找转移方程困扰了我很久,最后想出来了一个解决办法。
通过观察数据量大小可以知道所选元素的和的范围为Min(mat[i][j])<=sum<=m*Max(mat[i][j])
。
设置boolean数组dp[i][k]表示前i行之和为k是否存在。
转移方程为
d
p
[
i
]
[
k
+
m
a
t
[
i
]
[
j
]
]
=
d
p
[
i
−
1
]
[
k
]
,
k
∈
(
0
,
70
∗
70
]
dp[i][k+mat[i][j]]=dp[i-1][k],k\in(0,70*70]
dp[i][k+mat[i][j]]=dp[i−1][k],k∈(0,70∗70]
注意到第
i
i
i层只与第
i
−
1
i-1
i−1层有关, 所以无需二维数组。
时间复杂度为
O
(
n
m
2
M
a
x
(
m
a
t
[
i
]
[
j
]
)
)
O(nm^2Max(mat[i][j]))
O(nm2Max(mat[i][j]))
class Solution {
public int minimizeTheDifference(int[][] mat, int target) {
boolean[] dp = new boolean[70*70+1];
boolean[] dp2 = new boolean[70*70+1];
//初始化第一层
for(int i=0;i<mat[0].length;i++) {
dp[mat[0][i]]=true;
}
for(int i=1;i<mat.length;i++) {
dp2 = new boolean[70*70+1];
for(int j=0;j<mat[i].length;j++) {
for(int k=0;k<dp.length;k++) {
//上一层存在
if(dp[k]) {
dp2[k+mat[i][j]]=true;
}
}
}
//交换
for(int k=0;k<dp.length;k++) {
//上一层存在
if(dp2[k]) {
dp[k]=true;
}else
dp[k]=false;
}
}
int idx = 0;
while(true) {
if((target-idx>=0&&dp[target-idx])||(target+idx<dp.length&&dp[target+idx]))
return idx;
idx++;
}
}
}
1982. 从子集的和还原数组
题目描述
存在一个未知数组需要你进行还原,给你一个整数
n
表示该数组的长度。另给你一个数组sums
,由未知数组中全部2n
个子集的和组成(子集中的元素没有特定的顺序)。
返回一个长度为n
的数组ans
表示还原得到的未知数组。如果存在多种答案,只需返回其中任意一个。
如果可以由数组arr
删除部分元素(也可能不删除或全删除)得到数组sub
,那么数组sub
就是数组arr
的一个子集。sub
的元素之和就是arr
的一个子集的和。一个空数组的元素之和为0
。
注意: 生成的测试用例将保证至少存在一个正确答案。
示例 1:
输入: n = 3, sums = [-3,-2,-1,0,0,1,2,3]
输出:[1,2,-3]
解释:[1,2,-3] 能够满足给出的子集的和:
- []:和是 0
- [1]:和是 1
- [2]:和是 2
- [1,2]:和是 3
- [-3]:和是 -3
- [1,-3]:和是 -2
- [2,-3]:和是 -1
- [1,2,-3]:和是 0
注意,[1,2,-3] 的任何排列和 [-1,-2,3] 的任何排列都会被视作正确答案。
提示:
1 <= n <= 15
sums.length == 2^n
-10^4 <= sums[i] <= 10^4
解题思路
这题赛后补的时候看了很多题解,记录一下大佬的思路.
主要思路是先将数组集体加上最小值的相反数offset,变成全不为负的问题。
1.其中最小值必然是元素的解
2.从数组找删去该元素构成的子集和
3.重复第一步
最后在答案数组中找到一个子集和等于offset,对该子集元素乘以
−
1
-1
−1.
class Solution {
List<Integer> ans = new LinkedList<>();
public int[] recoverArray(int n, int[] sums) {
List<Integer> ans = new LinkedList<>();
TreeMap<Integer,Integer> other = new TreeMap<>();
Arrays.sort(sums);
int MinOffest = Math.abs(sums[0]);
for(int k:sums) {
MyHashMapPut(other,k+MinOffest);
}
// Integer integer = other.get(0);
// other.remove(0);
MyHashMapRemove(other,0);
while(ans.size()<n) {
//放入最小的值
int Min = other.firstKey();
//移除ans中子集构成的和
Remove(other,ans,Min);
ans.add(Min);
// MyHashMapRemove(other,Min);
}
int[] dp = new int[n];
for(int i=0;i<n;i++) {
dp[i]=ans.get(i);
}
Find(dp,MinOffest);
return dp;
}
private void Find(int[] ans, int target) {
back(0,0,ans,target,new Stack<Integer>());
}
private boolean back(int i, int sum, int[] ans, int target,Stack<Integer> roads) {
if(i>=ans.length) {
if(sum==target) {
while(!roads.isEmpty()) {
int temp = roads.pop();
ans[temp]*=-1;
}
return true;
}
return false;
}
roads.add(i);
if(back(i+1,sum+ans[i],ans,target,roads))
return true;
roads.pop();
if(back(i+1,sum,ans,target,roads))
return true;
return false;
}
private void Remove(Map<Integer, Integer> other, List<Integer> ans, int min) {
dfs(0,min,ans,other);
}
private void dfs(int i, int sum, List<Integer> ans, Map<Integer, Integer> other) {
if(i>=ans.size()) {
MyHashMapRemove(other,sum);
return;
}
dfs(i+1,sum+ans.get(i),ans,other);
dfs(i+1,sum,ans,other);
}
private void MyHashMapPut(Map<Integer, Integer> other, int k) {
if(other.containsKey(k)) {
other.put(k, other.get(k)+1);
}else {
other.put(k,1);
}
}
private void MyHashMapRemove(Map<Integer, Integer> other, int k) {
if(other.containsKey(k)) {
if(other.get(k)>0)
other.put(k, other.get(k)-1);
if(other.get(k)<=0) {
other.remove(k);
}
}
}
}
T4太难了。。。
赛后想了很久也没想明白。。。