763、划分字母区间

题目描述:

字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段。返回一个表示每个字符串片段的长度的列表。

示例 1:

输入: S = "ababcbacadefegdehijhklij"
输出: [9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。
注意:

S的长度在[1, 500]之间。
S只包含小写字母'a'到'z'。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-labels

注:题目要求malloc开辟数组

 

第一次解题思路(低效版本):

  1. 典型双指针思维,慢指针 k_s 指向输入数组头部,数值大小递增,快指针 k_e 指向输入数组尾部,数值大小递减;
  2. 对字母进行比较,如果不同,快指针-1,继续比较,直到字母相同为止,快指针停止移动,记录当前范围 [k_s_1,k_e_1];
  3. k_s+1,k_e回到尾部,再度执行步骤二,记录当前范围 [k_s_2,k_e_2] ,
    如果  k_s_1 < k_s_2 <  k_e_1,  k_e_2 > k_e_1,  则更新范围到 [k_s_1,k_e_2],
    如果  k_s_1 < k_s_2 < k_e_2 <= k_e_1,则无需更新范围,仍然是 [k_s_1,k_e_1]
    如果  k_e_1 < k_s_2,则表示上个字母区段已查找完毕,则可以直接记录已完成字母区段长度
  4. 重复步骤2、3,直到 k_s 指向尾部

犯错点:

  1. 做遍历的时候,忘记考虑了 ababc、cabab这种c独立存在的情况,导致错误,其实只需要在对k_s、k_e数值大小做判断的时候加上等号就可以了;
  2. 用了一个变量去记录已分类的字母数量,在更新范围的时候,忘记去更新这个变量了,导致错误。


时间复杂度 O(n^2)

int* partitionLabels(char * S, int* returnSize)
{
	int k_s = 0, k_e = 0, S_End = 0;    //k_s 指向数组头部的指针 k_e 指向数组尾部的指针

	int array_sum_old = 0, array_sum = 0;

	int *return_value = (int *)malloc(4);    //暂只开一个int空间,有需要时再加长
	*returnSize = 0;
    
	while (S[S_End] != '\0')
	{
		S_End++;
	}
	S_End--;	//定位到最后一个字符

	while (k_s <= S_End)        //易错点:如果没有等号,会漏掉 头部或尾部 的独立字母
	{                            //例如 cababd 的形式   (这个=号是头部还是尾部?忘记了)
		k_e = S_End;	//尾指针指向末尾

		while (k_s <= k_e)        //易错点:如果没有等号,会漏掉 头部或尾部 的独立字母
		{                            //例如 cababd 的形式  (这个=号是头部还是尾部?忘记了)
			if (S[k_s] != S[k_e])
				k_e--;
			else
			{
				if (k_s >= array_sum)		//头指针超出了已分类部分
				{
					array_sum_old = array_sum;	//保存已经完全分类的字符数量
					array_sum = k_e + 1;		//保存此次已经分类的字符数量

					return_value = realloc(return_value, (*returnSize + 2) * 4);

					return_value[*returnSize] = k_e - array_sum_old + 1;
					*returnSize += 1;
				}
				else //if (k_s >= array_sum_old)		//头指针在还未完全归类完成的部分
				{
					if (k_e >= array_sum)		//尾指针在完全未分类部分
					{
						return_value[*returnSize - 1] = k_e + 1 - array_sum_old;	//赋值
						array_sum = k_e + 1;	//错误点:漏写了这一句
					}
					else if (k_e < array_sum)
					{
						//在本次分类部分内部,不做任何操作
					}
				}

				break;
			}
		}

		k_s++;			//头指针递增
	}

	return return_value;
}

 

第二次解题思路:

  1. 题目限定只会出现26个小写字母,将每个字母第一次、最后一次出现的下标记录下来,形成26个范围,然后对这26个范围做一次区间合并;
  2. 做一次顺序(或逆序)遍历,确定字母出现范围;
  3. 再做一次顺序遍历,下标指针k_s,取出字母S[k_s]的范围  [s1,e1],与字母S[k_s+1]的范围 [s2,e2]的范围进行比较,若有重叠部分,则更新范围 [s1,e2],若无重叠部分,则[s1,e1]是已完成分类的区间范围,计算长度即可。

错误点:

  1. 代码中比较范围做更新的时候,多加了一个等号,导致输出数据 从1、2、3这样的形式,变成了1、1、2、2、3、3这样的形式,原因在于多做了一次比较。

 

int* partitionLabels(char * S, int* returnSize) 
{
	*returnSize = 0;	//先清零

	int *return_value = (int *)malloc(4);	//暂假设只有一个区段,开辟一个字节

	int character_array[26][2] = { 0 };//[][0] 首次出现下标  [][1]最后一次出现下标

	for (char i = 0; i < 26; i++)
		character_array[i][0] = -1;

	int s_index = 0;
	while (S[s_index] != '\0')
	{
		if (character_array[S[s_index] - 'a'][0] == -1)
		{
			character_array[S[s_index] - 'a'][0] = s_index;
		}

		if (s_index > character_array[S[s_index] - 'a'][1])
		{
			character_array[S[s_index] - 'a'][1] = s_index;
		}

		s_index++;
	}

	s_index = 0;
	int area_array[2] = { -1,-1 };

	while (S[s_index] != '\0')
	{
		if (area_array[0] == -1)
		{
			area_array[0] = character_array[S[s_index] - 'a'][0];	//确定当前区间起始下标
		}

		if ((character_array[S[s_index] - 'a'][1] > area_array[1]))
		{
			area_array[1] = character_array[S[s_index] - 'a'][1];	//确定当前区间结束下标
		}

		s_index++;

		if (s_index > area_array[1])	//一个错误点:如果加上等号,会导致多增加一个结束下标时的数组
		{
			*(return_value + *returnSize) = area_array[1] - area_array[0] + 1;
			*returnSize += 1;

			return_value = realloc(return_value, (*returnSize + 1) * 4);

			area_array[0] = -1;
			area_array[1] = -1;
		}
	}

	return return_value;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值