leetcode161周赛题解-贪心、栈、数学

3 篇文章 0 订阅
2 篇文章 0 订阅

1、交换字符使得字符串相同
有两个长度相同的字符串 s1 和 s2,且它们其中 只含有 字符 “x” 和 “y”,你需要通过「交换字符」的方式使这两个字符串相同。

每次「交换字符」的时候,你都可以在两个字符串中各选一个字符进行交换。

交换只能发生在两个不同的字符串之间,绝对不能发生在同一个字符串内部。也就是说,我们可以交换 s1[i] 和 s2[j],但不能交换 s1[i] 和 s1[j]。

最后,请你返回使 s1 和 s2 相同的最小交换次数,如果没有方法能够使得这两个字符串相同,则返回 -1 。

示例 1:

输入:s1 = "xx", s2 = "yy"
输出:1
解释:
交换 s1[0] 和 s2[1],得到 s1 = "yx",s2 = "yx"

示例 2:

输入:s1 = "xy", s2 = "yx"
输出:2
解释:
交换 s1[0] 和 s2[0],得到 s1 = "yy",s2 = "xx" 。
交换 s1[0] 和 s2[1],得到 s1 = "xy",s2 = "xy" 。
注意,你不能交换 s1[0] 和 s1[1] 使得 s1 变成 "yx",因为我们只能交换属于两个不同字符串的字符。

示例 3:

输入:s1 = "xx", s2 = "xy"
输出:-1
示例 4:

输入:s1 = "xxyyxyxyxx", s2 = "xyyxyxxxyx"
输出:4
 

提示:

1 <= s1.length, s2.length <= 1000
s1, s2 只包含 'x''y'

题目链接(leetcode)

思路:要达到最小交换次数,只能是发生交换的两个位置字母都一样,这样子就可以在只交换一次使两个位置的字母相同,如xx,yy。如果不一样的话,如xy,yx,就要换两次。注意当需要交换的位置数量为技术时返回-1,这时候无论怎么交换,都不可能使两个字符串相等的。

参考代码:

```java
class Solution {
    
    public int minimumSwap(String s1, String s2) 
    {
    	if(s1.length()!=s2.length())
    		return -1;
    	int cnt1=0,cnt2=0;
    	for(int i=0;i<s1.length();i++)
    	{
    		if(s1.charAt(i)!=s2.charAt(i))
    		{
    			if(s1.charAt(i)=='x')
    				cnt1++;
    			else
    				cnt2++;
    		}
    	}
    	if((cnt1+cnt2)%2==1)
    		return -1;
    	cnt1=(cnt1%2==0)?cnt1/2:cnt1/2+1;
    	cnt2=(cnt2%2==0)?cnt2/2:cnt2/2+1;
    	return cnt1+cnt2;
    		
    }
    
    
}

2、统计「优美子数组」
给你一个整数数组 nums 和一个整数 k。
如果某个子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」。
请返回这个数组中「优美子数组」的数目。

示例 1:

输入:nums = [1,1,2,1,1], k = 3
输出:2
解释:包含 3 个奇数的子数组是 [1,1,2,1][1,2,1,1]

示例 2:

输入:nums = [2,4,6], k = 1
输出:0
解释:数列中不包含任何奇数,所以不存在优美子数组。

示例 3:

输入:nums = [2,2,2,1,2,2,1,2,2,2], k = 2
输出:16

提示:

1 <= nums.length <= 50000
1 <= nums[i] <= 10^5
1 <= k <= nums.length

题目链接(leetcode)

思路:先计算出所有奇数位置的前面有多少个偶数,存放在list1中,然后计算所有奇数位置的后面有多少个偶数,存放在list2中。然后以k-1为区间长度遍历list1、list2,该位置的优美子数组个数=(该位置前面的偶数位置个数+1)*(该位置后面的的奇数位置个数+1)。

参考代码:

class Solution {
    
    public int numberOfSubarrays(int[] nums, int k) 
    {
    	int cnt=0;
    	for(int i=0;i<nums.length;i++)
    		if(nums[i]%2==1)
    		{
    			cnt++;
    		}
    	if(cnt<k)
    		return 0;
    	int[] arr=new int[nums.length];
    	int t=0;
    	for(int i=0;i<arr.length;i++)
    	{
    		if(nums[i]%2==0)
    			t++;
    		else
    		{
    			arr[i]=t;
    			t=0;
    		}
    	}
    	List<Integer> list1=new ArrayList<Integer>();
    	List<Integer> list2=new ArrayList<Integer>();
    	for(int i=0;i<arr.length;i++)
    	{
    		if(nums[i]%2==1)
    		{
    			if(list1.isEmpty())
    				list1.add(arr[i]);
    			else
    			{
    				list1.add(arr[i]);
    				list2.add(arr[i]);
    			}
    		}
    	}
    	list2.add(t);
    	int ans=0;
    	for(int i=0;i<list1.size();i++)
    	{
    		if(i+k-1<list2.size())
    		{
    			ans+=(list1.get(i)+1)*(list2.get(i+k-1)+1);
    		}
    	}
    	return ans;
    }
    
}

3、移除无效的括号
题目难度 Medium
给你一个由 ‘(’、’)’ 和小写字母组成的字符串 s。
你需要从字符串中删除最少数目的 ‘(’ 或者 ‘)’ (可以删除任意位置的括号),使得剩下的「括号字符串」有效。
请返回任意一个合法字符串。

有效「括号字符串」应当符合以下 任意一条 要求:

空字符串或只包含小写字母的字符串
可以被写作 AB(A 连接 B)的字符串,其中 A 和 B 都是有效「括号字符串」
可以被写作 (A) 的字符串,其中 A 是一个有效的「括号字符串」

示例 1:

输入:s = "lee(t(c)o)de)"
输出:"lee(t(c)o)de"
解释:"lee(t(co)de)" , "lee(t(c)ode)" 也是一个可行答案。

示例 2:

输入:s = "a)b(c)d"
输出:"ab(c)d"

示例 3:

输入:s = "))(("
输出:""
解释:空字符串也是有效的

示例 4:

输入:s = "(a(b(c)d)"
输出:"a(b(c)d)"

提示:

1 <= s.length <= 10^5
s[i] 可能是 '('')' 或英文小写字母

题目链接(leetcode)

思路:遍历字符串,利用栈存储"(“的下标,当遇到”)“时,弹出栈顶。当栈为空时,说明有多余的”)",将该位置上的字符删除。遍历完后,此时的栈中放的是多余的"(",将这些位置的"("删除。

参考代码:

class Solution {
    
    public String minRemoveToMakeValid(String s) 
    {
    	Stack<Integer> st=new Stack<Integer>();
    	char[] chs = s.toCharArray();
    	for(int i=0;i<chs.length;i++)
    	{
    		if(chs[i]==')')
    		{
    			if(st.isEmpty())
    				chs[i]=' ';
    			else
    				st.pop();
    		}
    		else if(chs[i]=='(')
    			st.push(i);
    	}
    	while(!st.isEmpty())
    		chs[st.pop()]=' ';
    	s=new String(chs);
    	s=s.replaceAll(" ", "");
    	return s;
    }
    
}

4、 检查「好数组」
给你一个正整数数组 nums,你需要从中任选一些子集,然后将子集中每一个数乘以一个 任意整数,并求出他们的和。
假如该和结果为 1,那么原数组就是一个「好数组」,则返回 True;否则请返回 False。

示例 1:

输入:nums = [12,5,7,23]
输出:true
解释:挑选数字 575*3 + 7*(-2) = 1

示例 2:

输入:nums = [29,6,10]
输出:true
解释:挑选数字 29, 61029*1 + 6*(-3) + 10*(-1) = 1

示例 3:

输入:nums = [3,6]
输出:false

提示:

1 <= nums.length <= 10^5
1 <= nums[i] <= 10^9

题目链接(leetcode)

思路:这题虽然是hard级别但只要想清楚了,其实并不难。首先是好数组的定义,子集中每一个数乘以一个 任意整数,它们的和结果为 1。换句话说,就是看他们的差值怎样才能拼凑成1,答案是只有当子集的最大公约数为1时才能拼凑成1,如4,6,最大公约数为2,所以无论怎么拼都无法拼凑出1。再比如3、5,最大公约数为1,3*2-5=1。这个想明白了就简单了。

参考代码:

class Solution {
    
    public boolean isGoodArray(int[] nums) 
    {
    	int dd=nums[0];
    	for(int i=0;i<nums.length;i++)
    		dd=gcd(dd,nums[i]);
    	return dd==1;
    }


	private int gcd(int m, int n) 
	{
		return m%n==0?n:gcd(n, m%n);
	}
    

    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值