【二分查找】【双指针】LeetCode:2565最少得分子序列

这篇具有很好参考价值的文章主要介绍了【二分查找】【双指针】LeetCode:2565最少得分子序列。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者推荐

【动态规划】【广度优先】LeetCode2258:逃离火灾

本文涉及的基础知识点

二分查找算法合集 有序向量的二分查找,初始化完成后,向量不会修改。
双指针: 用于计算子字符串是s的字符串的子系列。

题目

给你两个字符串 s 和 t 。
你可以从字符串 t 中删除任意数目的字符。
如果没有从字符串 t 中删除字符,那么得分为 0 ,否则:
令 left 为删除字符中的最小下标。
令 right 为删除字符中的最大下标。
字符串的得分为 right - left + 1 。
请你返回使 t 成为 s 子序列的最小得分。
一个字符串的 子序列 是从原字符串中删除一些字符后(也可以一个也不删除),剩余字符不改变顺序得到的字符串。(比方说 “ace” 是 “abcde” 的子序列,但是 “aec” 不是)。
示例 1:
输入:s = “abacaba”, t = “bzaa”
输出:1
解释:这个例子中,我们删除下标 1 处的字符 “z” (下标从 0 开始)。
字符串 t 变为 “baa” ,它是字符串 “abacaba” 的子序列,得分为 1 - 1 + 1 = 1 。
1 是能得到的最小得分。
示例 2:
输入:s = “cde”, t = “xyz”
输出:3
解释:这个例子中,我们将下标为 0, 1 和 2 处的字符 “x” ,“y” 和 “z” 删除(下标从 0 开始)。
字符串变成 “” ,它是字符串 “cde” 的子序列,得分为 2 - 0 + 1 = 3 。
3 是能得到的最小得分。
参数范围
1 <= s.length, t.length <= 105
s 和 t 都只包含小写英文字母。

分析

时间复杂度😮(nlogn)。枚举tRight,时间复杂度O(n);二分查找tLeft,时间复杂度O(logn)。令m_c是t的长度。tLeft=left-1,tRight=right+1。

变量解析

vLeft[i]=x 表示t[0,i]是s[0,x]子序列,x如果有多个值取最小值。如果x不存在,为任意大于等于m_c的值。显然是升序。
vRight[i]=x 表示t[t…)是s[x,…)子序列,如果x有多个值取最大值。如果x不存在,为任意小于0的值。

原理

将left和right直接的元素全部删除,积分不会增加,所以全删除。全删除后,只有两种情况:一,不删除。二,删除一处。t由两个部分组成。[0,tLeft]和[tRight,m_c)。如果左边为空,tLeft为-1;如果右边为空,tRight为m_c。sRight 为vRight[tRight],sLeft是小于sRight中的最大值。这样确保[0,sLeft]和[sRight…)没有重叠部分。sLeft在vLeft中的下标就是tLeft,tLeft必须小于tRight,否则[0,tLeft]和[tRight,m_c)会有重叠部分。

特殊情况

右边为空,在初始化vRight的时候,需要特殊处理,后续操作不需要。
如果vRight[tRight]非法,需要忽略。
tLeft为-1,不需特殊处理,就是左边为空。

代码

核心代码

class Solution {
public:
	int minimumScore(string s, string t) {
		m_c = t.length();
		//vLeft[i]=x,表示t[0,i]是s[0,x]子序列,x如果有多个值取最小值。如果x不存在,为任意大于等于m_c的值
		//vRight[i]=x,表示t[t...)是s[x,...)子序列,如果x有多个值取最大值。如果x不存在,为任意小于0的值。
		vector<int> vLeft(m_c, m_c),vRight(m_c,-1);
		{
			for (int i = 0, right=0; i < m_c; i++)
			{
				while ((right < s.length()) && (s[right] != t[i]))
				{
					right++;
				}
				vLeft[i] = right++;
			}
		}
		{
			for (int i = m_c - 1,left=s.length()-1; i >= 0; i--)
			{
				while ((left >= 0) && (s[left] != t[i]))
				{
					left--;
				}
				vRight[i] = left--;
			}
		}
		int iRet = m_c;
		vRight.emplace_back(s.length());//(right,m_c)为空不需要做特殊处理
		for (int tRight = 0 ; tRight < vRight.size(); tRight++)
		{
			const auto& sRight = vRight[tRight];
			if (sRight < 0)
			{
				continue;
			}
			//寻找第一个小于vRight[right]的索引
			int tLeft = std::lower_bound(vLeft.begin(), vLeft.end(), sRight)- vLeft.begin()-1;
			tLeft = min(tLeft, tRight - 1);
			iRet = min(iRet, tRight - tLeft - 1);
		}		
		return iRet;
	}
	int m_c;
};

测试用例

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		assert(v1[i] == v2[i]);
	}
}

template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

int main()
{
	string s, t;	
	{
		Solution slu;
		s = "abacaba", t = "bzaa";
		auto res = slu.minimumScore(s, t);
		Assert(1, res);
	}
	{
		Solution slu;
		s = "cde", t = "xyz";
		auto res = slu.minimumScore(s, t);
		Assert(3, res);
	}
	{
		Solution slu;
		s = "adebddaccdcabaade", t = "adbae";
		auto res = slu.minimumScore(s, t);
		Assert(0, res);
	}
	{
		Solution slu;
		s = "eceecbabe", t = "bdeaec";
		auto res = slu.minimumScore(s, t);
		Assert(4, res);
	}
	
	//CConsole::Out(res);
}

【二分查找】【双指针】LeetCode:2565最少得分子序列,# 算法题,leetcode,算法,二分查找,c++,双指针,最少得分,子系列

优化

第二轮循环,可以和第三轮循环合并,且改成双指针。可以直接用栈(向量)的出栈代替指针。第一轮寻找改成枚举s,更方便。

class Solution {
public:
	int minimumScore(string s, string t) {
		m_c = t.length();
		vector<int> vLeft;
		for (int is = 0; is < s.length(); is++)
		{
			if ((vLeft.size() < m_c) && (s[is] == t[vLeft.size()]))
			{
				vLeft.emplace_back(is);
			}
		}
		int iRet = m_c - vLeft.size(); //tRight==m_c
		for (int tRight = m_c - 1,sRight = s.length()-1 ; tRight >= 0; tRight--)
		{
			while ((sRight >= 0) && (s[sRight] != t[tRight]))
			{
				sRight--;
			}
			if (sRight < 0)
			{
				break;
			}
			while (vLeft.size() &&((vLeft.back() >= sRight) || (vLeft.size() > tRight)))
			{
				vLeft.pop_back();
			}
			iRet = min(iRet, tRight - (int)vLeft.size());
			sRight--;
		}	
		return iRet;
	}
	int m_c;
};

2023年3月旧代码

class Solution {
public:
int minimumScore(string s, string t) {
m_c = t.length();
m_c2 = s.length();
m_vLeft.assign(m_c, m_c2);
m_vRight.assign(m_c, -1);
{
int j = 0;
for (int i = 0; i < m_c; i++)
{
while ((j < m_c2) && (s[j] != t[i]))
{
j++;
}
if (s.length() == j)
{
break;
}
m_vLeft[i] = j++;
}
}
{
int j = s.length()-1 ;
for (int i = m_c - 1; i >= 0; i–)
{
while ((j >= 0 ) && (s[j] != t[i]))
{
j–;
}
if (-1 == j)
{
break;
}
m_vRight[i] = j–;
}
}
int left = -1, right = m_c;
for (; left + 1 != right;)
{
const int len = (left + right) / 2;
if (Can(len))
{
right = len;
}
else
{
left = len;
}
}
return right;
}
bool Can(int len)
{
for (int i = 0; i + len - 1 < m_c; i++)
{
bool bCan = true;
if (i + len == m_c)
{
bCan = m_vLeft[i - 1] < m_c2;
}
else if (0 == i)
{
bCan = m_vRight[i + len] > -1;
}
else
{
bCan = m_vLeft[i - 1] < m_vRight[i + len];
}
if (bCan)
{
return true;
}
}
return false;
}
vector m_vLeft, m_vRight;
int m_c;
int m_c2;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

【二分查找】【双指针】LeetCode:2565最少得分子序列,# 算法题,leetcode,算法,二分查找,c++,双指针,最少得分,子系列文章来源地址https://www.toymoban.com/news/detail-752090.html

到了这里,关于【二分查找】【双指针】LeetCode:2565最少得分子序列的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【算法|二分查找No.4】leetcode 852. 山脉数组的峰顶索引

    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望对大家有所帮助 🍓希望我们一起努力、成长,共同进步。

    2024年02月05日
    浏览(62)
  • LeetCode_二分搜索_中等_2594.修车的最少时间

    给你一个整数数组 ranks ,表示一些机械工的 能力值 。ranksi 是第 i 位机械工的能力值。能力值为 r 的机械工可以在 r * n 2 分钟内修好 n 辆车。 同时给你一个整数 cars ,表示总共需要修理的汽车数目。请你返回修理所有汽车最少需要多少时间。 注意:所有机械工可以同时修理

    2024年02月09日
    浏览(42)
  • 【经典LeetCode算法题目专栏分类】【第6期】二分查找系列:x的平方根、有效完全平方数、搜索二位矩阵、寻找旋转排序数组最小值

    《博主简介》 小伙伴们好,我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌ 更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍 感谢小伙伴 们点赞、关注! class   Solution :      def   mySqrt ( self ,  x :   int )   -   int :       

    2024年02月04日
    浏览(63)
  • leetcode 二分查找小结

    原始思路: 但是,挪一挪的步骤最差的时候时间复杂度也能达到O(n),所以另一种避免这种情况的思路是我们分别使用二分查找去寻找区间的最左和最右。 上面的寻找target的代码(while …)无法精确地找到最左,因此我们需要对其进行一些改写。关键是要在找到一个值的时候不

    2024年02月08日
    浏览(53)
  • # - LeetCode 704-二分查找 |LeetCode 27-移除元素

    ##  LeetCode 704-二分查找 -题目描述:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target , -写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  , 写一个函数搜索 nums

    2024年02月16日
    浏览(49)
  • LeetCode刷题笔记-704.二分查找

     我们定义target在一个左右都是关闭的区间,[left,right] while(left = right) 这里使用= 因为left == right 是有意义的 int mid = left + ((right - left) / 2) 这么写是为了防止溢出 常用操作 当nums[mid] target 将right = mid - 1因为target 不可能在mid处取到 当nums[mid] target 将left = mid + 1

    2024年02月11日
    浏览(53)
  • 每日一题(LeetCode)----二分查找(一)

    给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 示例 2: 示例 3: 提示: 1 = nums.length = 104 -104 = nums[i] = 104 nums 为 无重复元素 的 升序 排列数

    2024年02月08日
    浏览(49)
  • Leetcode 704.二分查找、27.移除元素

    暴力循环: 自己的思路 从左往右,遍历每个元素。 检查当前元素是否满足要求。 若满足要求则返回当前元素的下标。 时间复杂度:O(n); 空间复杂度:O(n); 二分查找: 题目给定的是一个升序的数组,即有序数组! 那么二分的前提是有序(或者具有某种特殊的性质!)。

    2024年02月17日
    浏览(50)
  • 代码随想录 LeetCode数组篇 二分查找

    # (简单)704. 二分查找 题目链接 代码随想录 - 二分查找思路 二分查找,思路很简单,但是在while循环left和right的比较是写=还是,还有right=mid还是right=mid-1容易混淆 需要想清楚对区间的定义,是[left,right],还是[left,right) (版本一,左闭右闭版本) (版本二,左闭右开) 题目

    2024年02月02日
    浏览(50)
  • 二分查找两个模板,leetcode35.搜索插入位置

    在有序数列中,查找某个元素是否存在 扩展一下: 在有序数列中(通常是非递减,可以有重复元素),查找第一个满足xx条件的元素 每次搜索区间减半,时间复杂度 O ( l o g n ) O(logn) O ( l o g n ) 1.初始边界为0和n-1,如果你的下标从1开始,那就是1和n,效果一样, 只需要确保初始

    2024年02月20日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包