力扣刷题之3106.满足距离约束且字典序最小的字符串

题干描述

给你一个字符串 s 和一个整数 k 。

定义函数 distance(s1, s2) ,用于衡量两个长度为 n 的字符串 s1 和 s2 之间的距离,即:

  • 字符 'a' 到 'z' 按 循环 顺序排列,对于区间 [0, n - 1] 中的 i ,计算所有「 s1[i] 和 s2[i] 之间 最小距离」的 和 

例如,distance("ab", "cd") == 4 ,且 distance("a", "z") == 1 。

你可以对字符串 s 执行 任意次 操作。在每次操作中,可以将 s 中的一个字母 改变  任意 其他小写英文字母。

返回一个字符串,表示在执行一些操作后你可以得到的 字典序最小 的字符串 t ,且满足 distance(s, t) <= k 。

示例 1:

输入:s = "zbbz", k = 3
输出:"aaaz"
解释:在这个例子中,可以执行以下操作:
将 s[0] 改为 'a' ,s 变为 "abbz" 。
将 s[1] 改为 'a' ,s 变为 "aabz" 。
将 s[2] 改为 'a' ,s 变为 "aaaz" 。
"zbbz" 和 "aaaz" 之间的距离等于 k = 3 。
可以证明 "aaaz" 是在任意次操作后能够得到的字典序最小的字符串。
因此,答案是 "aaaz" 。

示例 2:

输入:s = "xaxcd", k = 4
输出:"aawcd"
解释:在这个例子中,可以执行以下操作:
将 s[0] 改为 'a' ,s 变为 "aaxcd" 。
将 s[2] 改为 'w' ,s 变为 "aawcd" 。
"xaxcd" 和 "aawcd" 之间的距离等于 k = 4 。
可以证明 "aawcd" 是在任意次操作后能够得到的字典序最小的字符串。
因此,答案是 "aawcd" 。

示例 3:

输入:s = "lol", k = 0
输出:"lol"
解释:在这个例子中,k = 0,更改任何字符都会使得距离大于 0 。
因此,答案是 "lol" 。

题干解析

        首先我们需要先了解题干中的距离是指什么?事实上这个距离是一个在字符串操作中的概念,可以理解为一种特殊的字符变换距离。具体来说,它衡量的是两个字符串在最小变换次数从一个字符串变换为另一个字符串的难度。在这道题目中定义了一种字符的循环排列(即‘a’ 到‘z’,然后在回到‘a’),并规定了这种循环排列中的字符变换距离。

距离定义

我们来详细解释一下这种距离:

1.字符距离:两个字符之间的距离是他们在循环排列中的最小变换次数,例如
  • 字符‘a’到‘b’之间的距离是1,因为它们相邻。
  • 字符‘a’到‘z’的距离也是1,因为在循环排列中。从‘a’到‘z’只需要一次变换。
2.字符串距离:两个字符串之间的距离也是1,因为在循环排列中,从‘a’到‘z’只需要一次变换。

对于字符串“ab”和“cd”:

  • ‘a’到‘c’的距离是2(a->b->c) 。
  • ‘b’到‘d’的距离是2(b->c->d)。

         因此distance("ab", "cd") = 2 + 2 = 4

字典序

       字典序是指在字符串在字典中的排列顺序。例如,按照字典序排列时,apple排在banana之前。为了得到字典序最小的字符串,我们应该尽可能将字符改为字母表中最小的字母a。

题目分析

       这道题目要求我们通过人一次操作将给定的字符串s转换成一个新的字符串t,使得两个字符串s和t之间的距离不超过k,并且要使得到的字符串t在字典序上尽可能小。

1.字符循环排列:
  • 题目定义了字符a到z按循环顺序排列。两个字符之间的距离是它们在这个循环中的最小距离。例如,字符a和z之间的距离是1,因为它们在循环中的最小距离是1。
2.字符串距离:
  • 两个字符串之间的距离是所有对应位置字符之间的距离之和。例如,distance(“ab”, “cd”)等于4,因为a到c的距离是2,b到d的距离也是2。
3.操作:
  • 每次操作可以将字符串中的一个字母变成任何其他小写字母。

解题步骤 

1.计算字符串距离
  • 我们需要计算字符串s和t之间的距离。字符a到z按循环顺序排列,所以字符之间的距离是它们在循环中的最小距离。
2.贪心策略
  • 为了使字符串的字典序最小,我们应该尽可能多地将字符改为a,因为a在字典序中最小。
3.逐字符处理:

从字符串的左边开始,逐字符处理:

  • 计算将当前字符变成a所需的最小距离。
  • 如果距离小于等于k,则将当前字符变成a,并更新剩余的k。
  • 如果距离大于k,则根据剩余的k调整当前字符,确保不超过k的限制,然后结束。
#include <stdio.h>
#include <string.h>
#include <math.h>

char* getSmallestString(char* s, int k) {
	int len = strlen(s);
	for (int i = 0; i < len; ++i)
	{
		//计算将当前字符变成‘a’所需的最小距离
		int dis = fmin(s[i] - 'a', 'z' - s[i] + 1);
		if (dis <= k)
		{
			//距离小于等于k则将字母变成a
			s[i] = 'a';
			k -= dis;
		}
		else {
			//否则,将字符减去k,但需要考虑字符循环的情况
			int newChar = s[i] - k;
			if (newChar < 'a')
			{
				newChar += 26;//循环处理,回到z之后
			}
			s[i] = (char)newChar;
			break;
		}
	}
	return s;
}
int main() {
	char s1[] = "zbbz";
	int k1 = 3;
	printf("Result: %s\n", getSmallestString(s1, k1)); // 输出应为 "aaaz"

	char s2[] = "xaxcd";
	int k2 = 4;
	printf("Result: %s\n", getSmallestString(s2, k2)); // 输出应为 "aawcd"

	char s3[] = "lol";
	int k3 = 0;
	printf("Result: %s\n", getSmallestString(s3, k3)); // 输出应为 "lol"

	return 0;
}

 

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值