力扣刷题:575,分糖果(用快慢指针解决)及快慢指针模板,相关题目拓展 2021.11.1 每日一题

 

 

0:题目要求:

给定一个偶数长度的数组,其中不同的数字代表着不同种类的糖果,每一个数字代表一个糖果。你需要把这些糖果平均分给一个弟弟和一个妹妹。返回妹妹可以获得的最大糖果的种类数。

示例 1:

输入: candies = [1,1,2,2,3,3]
输出: 3
解析: 一共有三种种类的糖果,每一种都有两个。
     最优分配方案:妹妹获得[1,2,3],弟弟也获得[1,2,3]。这样使妹妹获得糖果的种类数最多。
示例 2 :

输入: candies = [1,1,2,3]
输出: 2
解析: 妹妹获得糖果[2,3],弟弟获得糖果[1,1],妹妹有两种不同的糖果,弟弟只有一种。这样使得妹妹可以获得的糖果种类数最多。
注意:

数组的长度为[2, 10,000],并且确定为偶数。
数组中数字的大小在范围[-100,000, 100,000]内

1:题目思路

 虽然题目给出的例子中都是非递减排序的,但是我们将答案中的

Arrays.sort(candyType);

 注释掉,不难发现测试样例中有不按顺序的

所以我本题的思路:

先对数组进行排序,然后消除排序后的数组中的相同元素。

这时候得到的数组中的不相同的元素的个数就是 数组中总共的糖果总数

然后 进行判别 因为是偶数个数组元素,如果 糖的总数的一半 比 糖的种类多,那么小女孩能拿到种类的显然是 糖的种类 。

即 共10个糖,种类6种,大于10/2=5;小女孩最多拿到六种中的五种

共10个糖,种类4种,小女孩最多拿到四种,返回四

2:变量设置和数据结构

经过上述分析我们不拿发现,调用Arrays类中的排序方法,有手就行。

关键是如何将排序后的数组筛选变的只有不重复元素

从而筛选后的数组长度==糖果总数。

这时候相信有些老铁就联想到了力扣

力扣中这个入门题,删除重复元素

我们直接调用快慢指针。

为什么强调他是快慢指针而不是双指针呢?

因为盯着两个指针一起走,考虑两个指针的情况
像个智障,不断地排除BUG情况,凑出来的代码勉强排除特殊情况,可以通过

上面的题力扣

例如我的第一次提交:


package leetcode.review.rereview;
/*
@author 作者 E-mail:
@version 创建时间:2021年10月31日 下午12:12:31
类说明:removeDuplicates 原地删除数组的多余元素
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
*/

public class RemoveDuplicates 
{
	    public int removeDuplicates(int[] nums) 
	    {
	        if(nums.length<=1)
	        {
	            return nums.length;//对长度0和1的数组进行处理
	        }
	        
	        int flag=nums[0];
			int slow=0;
	        int fast=0;
			for(;fast<nums.length;fast++)
			{
				if(nums[fast]==flag)
				{
					fast++;
	                {
	                    if(fast==nums.length)
	                    {
	                        break;
	                    }
	                }
				}
				if(nums[fast]!=flag)
				{
					slow++;
					flag=nums[fast];
					nums[slow]=nums[fast];
				}
			}
			return slow+1;
	    }
	
	   
		
	}
/*
此题我的编程思想从想法上来说还是很成熟的,风骚的双指针,快慢指针,当他等于前边已有的元素时直接fast++跳过他,
跳过之后再看下一个是否也还是跟旗帜相同,for循环和内置的fast++推动继续前进。当快指针指到不等于旗帜的数据时,交换,换位,对慢指针进行操作。但是需要考虑,当快指针指向边界并且这一整个数组都是同一个数字,如【1,1,1,1】时,会边界溢出。
计算机是非常精密和严格的。
同时需要对空数组,只有一个的数组进行特殊情况处理
其中【1,1】这种特殊情况,全是1,但是返回长度还是0,且根据程序编写的巧合性,第一次相等于flasg
fast++之后,他会返回for再执行语句三fast++,这时候fast就进不来了!
*/
//[1,1,2]
//[0,0,1,1,1,2,2,3,3,4]
//[0,0,1,1,1,2,2,3,3,4,55,55,66]
//[]
//[1]
//[1,2]
//[1,2]
//[1,1,1]

//执行出错信息:
//java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//  at line 19, Solution.removeDuplicates
//  at line 54, __DriverSolution__.__helper__
//  at line 84, __Driver__.main
//最后执行的输入:
//[1,1,1]


14点01分 
从2021.10.31日 12点开始
第一题是删除重复元素

盯着两个指针一起走
像个智障,不断地排除BUG情况,凑出来的
并且把这种错误思想引入了今天做的第二题移动零
其实没必要盯着两个指针
现针对第一题重做!

package leetcode.daily;
/*
@author 作者 E-mail:
@version 创建时间:2021年10月31日 下午2:03:47
类说明:第十四天,对本日做的第一题重做。
*/

public class Daily13_1_2 
{
	public int solution(int[] nums)
	{
		if(nums.length<2)
		{
			return nums.length;
		}
		
		int slow=0;
		int fast=0;
		int flag=nums[0];
		
		while(fast<nums.length)
		{
			if(nums[fast]==flag)
			{
				fast++;
			//此处还要加,防止fast出界
			{if(fast==nums.length) break;}
			}
			if(nums[fast]!=flag)
			{
				nums[slow++]=nums[fast];
				flag=nums[fast];
				
			}
		}
		
		return slow+1;
	}

}


class Solution 
{
     public int removeDuplicates(int[] nums) 
    {
        		if(nums.length<2)
		{
			return nums.length;
		}
		
		int slow=1;
		int fast=0;
		int flag=nums[0];
		
	for(;fast<nums.length;fast++)
    {
			if(nums[fast]!=flag)
			{
				nums[slow++]=nums[fast];
				flag=nums[fast];
			
			}
		}
		
		return slow;
	}

}
 

双指针里for和while是一样的,记住模板稍加更改就可

这样我们通过刷题整理得到了双指针的框架:,

双指针,一左一右:left||right

快慢指针,一快一慢:slow和fast

两种循环方式:

while和for 其中用while时,

需要在循环内对fast(right)指针自加

for循环中(依赖for自加即可)

所需要空间为原数组

3:代码求解:

class Solution
 {
    public int distributeCandies(int[] candyType)
    {
		
		int bornlen=candyType.length;
		if(bornlen==2)
		{
			return 1;
		}
		Arrays.parallelSort(candyType);
		int left=1;
		int right=0;
		int flag=candyType[0];
		for(;right<bornlen;right++)
		{
			if(candyType[right]!=flag)
			{
				flag=candyType[right];
				candyType[left++]=candyType[right];
			}
			
		}
		if(left>bornlen/2)
		{
			return bornlen/2;
		}
		return left;
		
	}

}

4:快慢指针总结:

为何叫做快慢指针,而不叫双指针

因为如

#977 有序数组的平方

这种题,用到的双指针,一左一右,两个一个在数组0位置,一个在数组末尾,需要同时盯两个

指针力扣

但是本题,快慢指针一起从头开始,盯着一个即可

for(int right=0;right<数组名.length;fast++)
{
    if(不满足条件)
    {    
        看题目要求执不执行操作
        //如果是while循环,此处fast应该自加,推动fast快指针去检查下一个位置
    }
    if(满足条件)
    {
        //通常是对慢指针进行操作,如换位,删除,进位,移动,退位
        //之后慢指针位置变化(一般是自加)
    }
}



5:给老铁们留了几道快慢指针的题目练手

  • 26.删除排序数组中的重复项
  • 283.移动零
  • 844.比较含退格的字符串
  • 977.有序数组的平方

  • 针对移动零,以下是刷题时候的笔记和源码:
  •    public void moveZeroes(int[] nums) 
        {
            //本题设置两个指针,快慢指针,慢指针停在0,快指针从0出发往后找非0,
            //找到之后,换位置,这样从头开始,保证了原有的顺序性,然后这样避免了那种两个指针一头一尾的,换过来没顺序。
    
            int fast=0;
            int slow=0;
            int n=nums.length;
            for(;fast<n;fast++)
            {   public void moveZeroes(int[] nums) 
        {
            //本题设置两个指针,快慢指针,慢指针停在0,快指针从0出发往后找非0,
            //找到之后,换位置,这样从头开始,保证了原有的顺序性,然后这样避免了那种两个指针一头一尾的,换过来没顺序。
    
            int fast=0;
            int slow=0;
            int n=nums.length;
            for(;fast<n;fast++)
            {
                if(nums[fast]==0)
                {
                    fast++;//此处其实不用管,因为你的fast无非就两种情况,fast为0,fast不为0
    //此处判断fast不为0,且++,出去了还要再加,还要防止下面对此处的fast+1之后的新fast判断,且看出不出bug,不如直接不管
                }
                if(nums[fast]!=0)
                {//此处更加不对,你的意思就是从0开始一个一个判断,应该是交换而不是简单的覆盖。
                    nums[slow]=nums[fast];//直接swap交换操作,交换之后,再对慢指针进行操作。这种快慢指针就是应该紧盯着一个指针进行操作。
    //并且为什么叫做快慢指针不叫作双指针,感觉它的意义就在于从头开始,并且将快的边界设置在数组长度,紧盯着快的,符合条件对慢指针操作!!!
    //像上一个题删除重复元素,同时紧盯快慢指针,容易出bug且没有模板通用性!
                    slow++;
                    n--;
                }
                if(nums[slow]!=0)
                {
                    slow++;
                }
            }
            for(int i=slow;i<nums.length;i++)
            {
                nums[i]=0;
            }
    
    
                if(nums[fast]!=0)
                {
                    nums[slow]=nums[fast];
                    slow++;
                    n--;
    	}
                if(nums[slow]!=0)
                {
                    slow++;
                }
            }
            for(int i=slow;i<nums.length;i++)
            {
                nums[i]=0;
            }
    
    //其实快慢指针就是,模板就是
    从0开始,一快一慢,快的去找,找到操作,紧盯着一个指针就行!
    

#其他

小菜鸡我正在力扣刷题。

双指针,快慢指针,螺旋数组等,日拱一卒不断进步,

觉得写得还不错的老铁点个关注,相互交流学习呀!

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

傻根根呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值