当前位置: 首页 > news >正文

3213. 最小代价构造字符串

Powered by:NEFU AB-IN

Link

文章目录

  • 3213. 最小代价构造字符串
    • 题意
    • 思路
    • 代码

3213. 最小代价构造字符串

题意

给你一个字符串 target、一个字符串数组 words 以及一个整数数组 costs,这两个数组长度相同。

设想一个空字符串 s。

你可以执行以下操作任意次数(包括零次):

选择一个在范围 [0, words.length - 1] 的索引 i。
将 words[i] 追加到 s。
该操作的成本是 costs[i]。
返回使 s 等于 target 的 最小 成本。如果不可能,返回 -1。

思路

字典树/字符串哈希 + dp

  1. 使用 Trie 树存储单词和成本:
    我们将所有的单词和对应的成本插入到一个 Trie 树中。Trie 树是一种多叉树,可以快速查找以某个前缀开头的所有单词。
    这样我们就能在 Trie 树中快速查找到以 target 中某个位置开始的所有前缀单词及其成本。
  2. 动态规划(Dynamic Programming):
    使用一个动态规划数组 dp,其中 dp[i] 表示构造 target 的前 i 个字符的最小成本。
    初始化 dp[0] = 0,表示构造空字符串的成本为 0,其他位置初始化为无穷大,表示尚未计算到该位置。
  3. 遍历目标字符串:
    对于目标字符串 target 的每一个位置 i,如果 dp[i] 是无穷大,表示不能从当前位置开始构造,则跳过。
    否则,使用 Trie 树的 search 方法,从当前位置 i 开始查找所有可能的前缀及其成本。
    对于每一个找到的前缀,更新 dp 数组:dp[i + length] = min(dp[i + length], dp[i] + cost),表示从当前位置 i 开始构造到 i + length 的最小成本。

代码

# 3.8.19 import
import random
from collections import Counter, defaultdict, deque
from datetime import datetime, timedelta
from functools import lru_cache
from heapq import heapify, heappop, heappush, nlargest, nsmallest
from itertools import combinations, compress, permutations, starmap, tee
from math import ceil, fabs, floor, gcd, log, sqrt
from string import ascii_lowercase, ascii_uppercase
from sys import exit, setrecursionlimit, stdin
from typing import Any, Dict, List, Tuple, TypeVar, Union# Constants
TYPE = TypeVar('TYPE')
N = int(2e5 + 10)  # If using AR, modify accordingly
M = int(20)  # If using AR, modify accordingly
INF = int(2e9)
OFFSET = int(100)# Set recursion limit
setrecursionlimit(INF)class Arr:array = staticmethod(lambda x=0, size=N: [x] * size)array2d = staticmethod(lambda x=0, rows=N, cols=M: [Arr.array(x, cols) for _ in range(rows)])graph = staticmethod(lambda size=N: [[] for _ in range(size)])@staticmethoddef to_1_indexed(data: Union[List, str, List[List]]):"""Adds a zero prefix to the data and returns the modified data and its length."""if isinstance(data, list):if all(isinstance(item, list) for item in data):  # Check if it's a 2D arraynew_data = [[0] * (len(data[0]) + 1)] + [[0] + row for row in data]return new_data, len(new_data) - 1, len(new_data[0]) - 1else:new_data = [0] + datareturn new_data, len(new_data) - 1elif isinstance(data, str):new_data = '0' + datareturn new_data, len(new_data) - 1else:raise TypeError("Input must be a list, a 2D list, or a string")class Str:letter_to_num = staticmethod(lambda x: ord(x.upper()) - 65)  # A -> 0num_to_letter = staticmethod(lambda x: ascii_uppercase[x])  # 0 -> Aremoveprefix = staticmethod(lambda s, prefix: s[len(prefix):] if s.startswith(prefix) else s)removesuffix = staticmethod(lambda s, suffix: s[:-len(suffix)] if s.endswith(suffix) else s)class Math:max = staticmethod(lambda a, b: a if a > b else b)min = staticmethod(lambda a, b: a if a < b else b)class IO:input = staticmethod(lambda: stdin.readline().rstrip("\r\n"))read = staticmethod(lambda: map(int, IO.input().split()))read_list = staticmethod(lambda: list(IO.read()))class Std:@staticmethoddef find(container: Union[List[TYPE], str], value: TYPE):"""Returns the index of value in container or -1 if value is not found."""if isinstance(container, list):try:return container.index(value)except ValueError:return -1elif isinstance(container, str):return container.find(value)@staticmethoddef pairwise(iterable):"""Return successive overlapping pairs taken from the input iterable."""a, b = tee(iterable)next(b, None)return zip(a, b)@staticmethoddef bisect_left(a, x, key=lambda y: y):"""The insertion point is the first position where the element is not less than x."""left, right = 0, len(a)while left < right:mid = (left + right) >> 1if key(a[mid]) < x:left = mid + 1else:right = midreturn left@staticmethoddef bisect_right(a, x, key=lambda y: y):"""The insertion point is the first position where the element is greater than x."""left, right = 0, len(a)while left < right:mid = (left + right) >> 1if key(a[mid]) <= x:left = mid + 1else:right = midreturn leftclass SparseTable:def __init__(self, data: list, func=lambda x, y: x | y):"""Initialize the Sparse Table with the given data and function."""self.func = funcself.st = [list(data)]i, n = 1, len(self.st[0])while 2 * i <= n:pre = self.st[-1]self.st.append([func(pre[j], pre[j + i]) for j in range(n - 2 * i + 1)])i <<= 1def query(self, begin: int, end: int):"""Query the combined result over the interval [begin, end]."""lg = (end - begin + 1).bit_length() - 1return self.func(self.st[lg][begin], self.st[lg][end - (1 << lg) + 1])class TrieNode:def __init__(self):"""Initialize children dictionary and cost. The trie tree is a 26-ary tree."""self.children = {}self.cost = INFdef add(self, word, cost):"""Add a word to the trie with the associated cost."""node = selffor c in word:if c not in node.children:node.children[c] = Std.TrieNode()node = node.children[c]node.cost = min(node.cost, cost)def search(self, word):"""Search for prefixes of 'word' in the trie and return their lengths and costs."""node = selfans = []for i, c in enumerate(word):if c not in node.children:breaknode = node.children[c]if node.cost != INF:ans.append([i + 1, node.cost])  # i + 1 to denote length from startreturn ansclass StringHash:def __init__(self, s: str, mod: int = 1_070_777_777):"""Initialize the StringHash object with the string, base, and mod."""self.s = sself.mod = modself.base = random.randint(8 * 10 ** 8, 9 * 10 ** 8)self.n = len(s)self.pow_base = [1] + Arr.array(0, self.n)  # pow_base[i] = BASE^iself.pre_hash = Arr.array(0, self.n + 1)  # pre_hash[i] = hash(s[:i])self._compute_hash()def _compute_hash(self):"""Compute the prefix hash values and power of base values for the string."""for i, b in enumerate(self.s):self.pow_base[i + 1] = self.pow_base[i] * self.base % self.modself.pre_hash[i + 1] = (self.pre_hash[i] * self.base + ord(b)) % self.moddef get_sub_hash(self, l: int, r: int) -> int:"""Get the hash value of the substring s[l:r+1] """return (self.pre_hash[r + 1] - self.pre_hash[l] * self.pow_base[r - l + 1] % self.mod + self.mod) % self.moddef get_full_hash(self) -> int:"""Get the hash value of the full string"""return self.pre_hash[self.n]def compute_hash(self, word: str) -> int:"""Compute the hash value of a given word using the object's base and mod."""h = 0for b in word:h = (h * self.base + ord(b)) % self.modreturn h# ————————————————————— Division line ——————————————————————class Solution:def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:# Build the Trietrie = Std.TrieNode()for word, cost in zip(words, costs):trie.add(word, cost)n = len(target)dp = Arr.array(INF, n + 1)dp[0] = 0# Dynamic programming to calculate the minimum costfor i in range(n):if dp[i] == INF:continuefor length, cost in trie.search(target[i:]):dp[i + length] = min(dp[i + length], dp[i] + cost)return dp[n] if dp[n] != INF else -1class Solution:def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:n = len(target)target_hash = Std.StringHash(target)# 每个 words[i] 的哈希值 -> 最小成本min_cost = defaultdict(lambda: INF)for w, c in zip(words, costs):h = target_hash.compute_hash(w)min_cost[h] = min(min_cost[h], c)# 获取所有唯一的单词长度sorted_lens = sorted(set(map(len, words)))dp = Arr.array(INF, n + 1)dp[0] = 0for i in range(n):if dp[i] == INF:continuefor sz in sorted_lens:if i + sz > n:break# 计算子串 target[i:i+sz] 的哈希值sub_hash = target_hash.get_sub_hash(i, i + sz - 1)dp[i + sz] = min(dp[i + sz], dp[i] + min_cost[sub_hash])return -1 if dp[n] == INF else dp[n]

相关文章:

3213. 最小代价构造字符串

Powered by:NEFU AB-IN Link 文章目录 3213. 最小代价构造字符串题意思路代码 3213. 最小代价构造字符串 题意 给你一个字符串 target、一个字符串数组 words 以及一个整数数组 costs&#xff0c;这两个数组长度相同。 设想一个空字符串 s。 你可以执行以下操作任意次数&a…...

提取重复数据

直接上控制台代码&#xff1a; Module Module1Sub Main()Console.WriteLine("请输入数据&#xff0c;以""&#xff0c;""相隔&#xff1a;")Dim str As String Console.ReadLineDim result From x In str.Split(",")Group By x Int…...

Go语言标准库之log和三方库zap

一、Log 1.1 logger基本使用 Go语言内置的log包实现了简单的日志服务。本包也提供了一个预定义的“标准”logger&#xff0c;可以通过调用函数Print系列(Print|Printf|Println)、Fatal系列&#xff08;Fatal|Fatalf|Fatalln)、和Panic系列&#xff08;Panic|Panicf|Panicln)来…...

Linux:进程终止和进程替换

Linux&#xff1a;Linux&#xff1a;进程终止和进程替换 一、进程终止1.1 进程退出场景和创建退出方式 1.2 exit 和 _exit区别二、进程程序替换2.1 进程替换函数2.2 函数解释及命名解释函数解释命名解释 2.3 单进程程序替换&#xff08;无子进程&#xff09;2.3.1 带l函数进程替…...

使用Java实现异步消息处理与队列消费

使用Java实现异步消息处理与队列消费 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在现代软件系统中&#xff0c;处理异步消息和队列消费是常见的需求。通过…...

使用C++实现ATM系统,谈谈思路及代码实现

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…...

相机光学(二十四)——CRA角度

CRA角度 0.参考资料1.什么是CRA角度2.为什么 CRA 会导致luma shading3.为什么 CRA 会导致color shading4.CRA相差过大的具体表现5.CRA Matching6.怎样选择sensor的CRA 0.参考资料 1.芯片CRA角度与镜头的匹配关系&#xff08;一&#xff09;   2.芯片CRA角度与镜头选型的匹配关…...

python函数和c的区别有哪些

Python有很多内置函数&#xff08;build in function&#xff09;&#xff0c;不需要写头文件&#xff0c;Python还有很多强大的模块&#xff0c;需要时导入便可。C语言在这一点上远不及Python&#xff0c;大多时候都需要自己手动实现。 C语言中的函数&#xff0c;有着严格的顺…...

速看!这主食冻干评测极可能被商家恶意举报~PR、希喂和SC真实测评

我是一名专注于宠物健康的营养师&#xff0c;日常大部分时间都在与猫咪和狗狗为伴&#xff0c;对它们入店时的身体状况往往能迅速做出初步判断。当前&#xff0c;多数家养猫咪面临的肥胖和肝损伤问题尤为突出&#xff0c;尽管医疗干预能缓解病情&#xff0c;但要从根本上解决还…...

股票数据分析(K线图、均值图、MACD图、RSI图)--股票日数据

数据 数据是上证指数日行情数据&#xff0c;股票代码000002.sz&#xff0c;原始数据shdata示例如下&#xff1a; 读取数据&#xff1a; import numpy as np import pandas as pd import mplfinance as mpf import matplotlib.pyplot as plt from datetime import datetime imp…...

重写equals()方法为什么同时要重写hashcode()

equals()方法 equals()方法是Object类中的一个方法&#xff0c;在Object类中&#xff0c;equals等同于。 在不同的类中&#xff0c;往往会对equals()按需求进行重写。重写的目的都是&#xff1a;用于比较两个对象是否 "相等"。如果两个对象的内容相同&#xff0c;那…...

安全及应用(更新)

一、账号安全 1.1系统帐号清理 #查看/sbin/nologin结尾的文件并统计 [rootrootlocalhost ~]# grep /sbin/nologin$ /etc/passwd |wc -l 40#查看apache登录的shell [rootrootlocalhost ~]# grep apache /etc/passwd apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin#改变…...

Hadoop权威指南-读书笔记-03-Hadoop分布式文件系统

Hadoop权威指南-读书笔记 记录一下读这本书的时候觉得有意思或者重要的点~ 还是老样子~挑重点记录哈&#x1f601;有兴趣的小伙伴可以去看看原著&#x1f60a; 第三章 Hadoop分布式文件系统 当数据集的大小超过一台独立的物理计算机的存储能力时&#xff0c;就有必要对它进行分…...

Rust入门实战 编写Minecraft启动器#2建立资源模型

首发于Enaium的个人博客 我们需要声明几个结构体来存储游戏的资源信息&#xff0c;之后我们需要将json文件解析成这几个结构体&#xff0c;所以我们需要添加serde依赖。 serde { version "1.0", features ["derive"] }资源相关asset.rs use serde::De…...

小白学C++(第一天)基础入门

温馨提醒&#xff1a;本篇文章&#xff0c;请各位c基础不行的童鞋不要贸然观看 C的第一个程序 第一个关键字namespace namespace 是定义空间的名字的关键字&#xff0c;使用格式格式如下&#xff1a; namespace 空间名 { } 其中{ }内的命名空间的成员&#xff0c;可以定义…...

谷歌正在试行人脸识别办公室安全系统

内容提要&#xff1a; &#x1f9ff;据美国消费者新闻与商业频道 CNBC 获悉&#xff0c;谷歌正在为其企业园区安全测试面部追踪技术。 &#x1f9ff;测试最初在华盛顿州柯克兰的一间办公室进行。 &#x1f9ff;一份内部文件称&#xff0c;谷歌的安全和弹性服务 (GSRS) 团队将…...

【CSS01】CSS概述,使用样式的必要性,CSS语法及选择器

文章目录 一、什么是样式二、使用样式的必要性三、使用样式的几种方式四、CSS基本语法&#xff1a;五、CSS的注释六、CSS选择器——重点相关单词 一、什么是样式 概念&#xff1a; Cascade [kˈskeɪd] Style Sheet [ʃiːt] 级联样式单/表&#xff0c;层叠样式表 CSS有化腐…...

PostgreSQL的pg_bulkload工具

PostgreSQL的pg_bulkload工具 pg_bulkload 是一个针对 PostgreSQL 提供高性能批量数据加载的工具。相较于内置的 COPY 命令&#xff0c;pg_bulkload 更加灵活并且在许多情况下性能更高。它支持数据的强制加载、数据过滤、数据转换以及错误处理等多种功能&#xff0c;非常适合需…...

【Java伴学笔记】Day-01 命令行|环境|编译解释运行|Java的相关分支|Java的特性|字面量

一、关于命令行 图形化界面的缺点 需要加载图片等一系列资源 效率较低 命令行 CMDMicrosoft Learn-CMDWindows CMD常用命令大全&#xff08;值得收藏&#xff09; 二、环境 什么是JDK JDK是Java Development Kit的缩写&#xff0c;意为Java开发工具包。它是一个用于开发Java应用…...

如何使用Vue3创建在线三维模型展示?

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 代码相关的技术博客 代码应用场景介绍 本段代码使用 RoughJS 库在 HTML5 Canvas 上创建了手绘风格的图像&#xff0c;展示了 RoughJS 库的强大功能&#xff0c;可用于创建具有有机手绘外观的图形。 代码基本…...

使用ndoe实现自动化完成增删改查接口

使用ndoe实现自动化完成增删改查接口 最近工作内容比较繁琐&#xff0c;手里需要开发的项目需求比较多&#xff0c;常常在多个项目之间来回切换&#xff0c;有时候某些分支都不知道自己开发了什么、做了哪些需求&#xff0c; 使用手写笔记的方式去记录分支到头来也是眼花缭乱&a…...

排序 -- 手撕归并排序(递归和非递归写法)

一、基本思想 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列有…...

防火墙基础及登录(华为)

目录 防火墙概述防火墙发展进程包过滤防火墙代理防火墙状态检测防火墙UTM下一代防火墙&#xff08;NGFW&#xff09; 防火墙分类按物理特性划分软件防火墙硬件防火墙 按性能划分百兆级别和千兆级别 按防火墙结构划分单一主机防火墙路由集成式防火墙分布式防火墙 华为防火墙利用…...

【Vue】使用html、css实现鱼骨组件

文章目录 预览图组件测试案例 预览图 组件 <template><div class"context"><div class"top"><div class"label-context"><div class"label" v-for"(item, index) in value" :key"index&qu…...

Python的多态

在 Python 中&#xff0c;多态&#xff08;Polymorphism&#xff09;是指不同的对象可以对相同的消息&#xff08;方法调用&#xff09;做出不同的响应。 简单来说&#xff0c;多态允许使用一个统一的接口来操作不同类型的对象&#xff0c;而这些对象会根据自身的类型来执行相应…...

001uboot体验

1.uboot的作用&#xff1a; 上电->uboot启动->关闭看门狗、初始化时钟、sdram、uart等外设->把内核文件从flash读取到SDRAM->引导内核启动->挂载根文件系统->启动根文件系统的应用程序 2.uboot编译 uboot是一个通用的裸机程序&#xff0c;为了适应各种芯片&…...

Flask之电子邮件

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 目录 一、使用Flask-Mail发送电子邮件 1.1、配置Flask-Mail 1.2、构建邮件数据 1.3、发送邮件 二、使用事务邮件服务SendGrid 2.1、注册SendGr…...

Vue 2 与 ECharts:结合使用实现动态数据可视化

在现代前端开发中&#xff0c;数据可视化变得越来越重要。ECharts 是一个强大的数据可视化库&#xff0c;而 Vue 2 则是一个流行的前端框架。本文将介绍如何将 Vue 2 和 ECharts 结合使用&#xff0c;以实现动态数据可视化。 安装与配置 首先&#xff0c;确保你的项目中已经安…...

.net core Redis 使用有序集合实现延迟队列

Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。 不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。 有序集合的成员是唯一的,但分数(score)却可以重复。 集合是通过哈希表实现的&#xf…...

linux 安装Openjdk1.8

一、在线安装 1、更新软件包 sudo apt-get update 2、安装openjdk sudo apt-get install openjdk-8-jdk 3、配置openjdk1.8 openjdk默认会安装在/usr/lib/jvm/java-8-openjdk-amd64 vim ~/.bashrc export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 export JRE_HOME${J…...