leetcode255场周赛

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绝对差
返回最小的绝对差
ab两数字的绝对差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[i1][k],k(0,7070]
注意到第 i i i层只与第 i − 1 i-1 i1层有关, 所以无需二维数组。
时间复杂度为 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太难了。。。
赛后想了很久也没想明白。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值