2023-08-18:用go写算法。你会得到一个字符串 text,

你应该把它分成 k 个子字符串 (subtext1, subtext2,…, subtextk)。

要求满足:

subtexti 是 非空 字符串,

所有子字符串的连接等于 text ,

( 即subtext1 + subtext2 + ... + subtextk == text ),

subtexti == subtextk - i + 1 表示所有 i 的有效值( 即 1 <= i <= k )。

返回k可能最大值。

输入:text = "ghiabcdefhelloadamhelloabcdefghi"。

输出:7。

解释:我们可以把字符串拆分成 "(ghi)(abcdef)(hello)(adam)(hello)(abcdef)(ghi)"。

来自小红书、谷歌、Bloomberg、微软、亚马逊、字节跳动、摩根大通、Uber。

来自左程云

答案2023-08-18:

这两种算法的步骤可以概括如下:

方法1:longestDecomposition1(text)

1.初始化变量 s 为文本的字节数组,变量 n 为文本长度,变量 lr 分别指向字节数组的开头和末尾,变量 ans 初始化为 0。

2.使用双指针法,当 l 小于等于 r 时进行循环:

  • 初始化变量 size 为 1。

  • 在一个循环内,通过比较子字符串是否相同来确定 size 的值,直到 size 使得剩余的子字符串无法再被分割为相同的子字符串。

  • 如果 size 使得剩余的子字符串可以被分割为相同的子字符串,则将 ans 增加 2。

  • 向右移动 l 和向左移动 r,使其分别指向剩余子字符串的新开头和新结尾。

3.如果 r 恰好等于 l-1,则返回 ans,否则返回 ans + 1

方法2:longestDecomposition2(text)

1.初始化变量 s 为文本的字节数组,变量 n 为文本长度,通过调用 generateDC3 函数生成 dc3 结构体。

2.初始化变量 rankdc3 结构体中的 Rank 切片,初始化变量 rmq 为通过调用 NewRMQ 函数生成的 RMQ 结构体,变量 lr 分别指向字节数组的开头和末尾,变量 ans 初始化为 0。

3.使用双指针法,当 l 小于等于 r 时进行循环:

  • 初始化变量 size 为 1。

  • 在一个循环内,通过比较子字符串是否相同来确定 size 的值,直到 size 使得剩余的子字符串无法再被分割为相同的子字符串。

  • 如果 size 使得剩余的子字符串可以被分割为相同的子字符串,则将 ans 增加 2。

  • 向右移动 l 和向左移动 r,使其分别指向剩余子字符串的新开头和新结尾。

4.如果 r 恰好等于 l-1,则返回 ans,否则返回 ans + 1

复杂度分析:

最初的算法longestDecomposition1的时间复杂度和空间复杂度如下:

  • 时间复杂度:O(n^2),其中n为输入字符串text的长度。

  • 空间复杂度:O(n),需要额外的空间来存储中间计算结果。

优化后的算法longestDecomposition2使用了DC3RMQ的数据结构,并进行了分块处理,因此时间复杂度和空间复杂度如下:

  • 时间复杂度:O(n log n),其中n为输入字符串text的长度。

  • 空间复杂度:O(n),需要额外的空间来存储中间计算结果。

总结:优化后的算法longestDecomposition2虽然时间复杂度更低,但空间复杂度和初次计算的算法longestDecomposition1相同,都为O(n)。

go语言完整代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. )
  7. func longestDecomposition1(text string) int {
  8. if len(text) == 1 {
  9. return 1
  10. }
  11. s := []byte(text)
  12. n := len(s)
  13. l := 0
  14. r := n - 1
  15. ans := 0
  16. for l <= r {
  17. size := 1
  18. for 2*size <= r-l+1 {
  19. if same1(s, l, r, size) {
  20. break
  21. }
  22. size++
  23. }
  24. if 2*size <= r-l+1 {
  25. ans += 2
  26. }
  27. l += size
  28. r -= size
  29. }
  30. if r == l-1 {
  31. return ans
  32. }
  33. return ans + 1
  34. }
  35. func same1(s []byte, l, r, size int) bool {
  36. for i, j := l, r-size+1; j <= r; i, j = i+1, j+1 {
  37. if s[i] != s[j] {
  38. return false
  39. }
  40. }
  41. return true
  42. }
  43. func longestDecomposition2(str string) int {
  44. if len(str) == 1 {
  45. return 1
  46. }
  47. s := []byte(str)
  48. n := len(s)
  49. dc3 := generateDC3(s, n)
  50. rank := dc3.Rank
  51. rmq := NewRMQ(dc3.Height)
  52. l := 0
  53. r := n - 1
  54. ans := 0
  55. for l <= r {
  56. size := 1
  57. for ; 2*size <= r-l+1; size++ {
  58. if same2(rank, rmq, l, r, size) {
  59. break
  60. }
  61. }
  62. if 2*size <= r-l+1 {
  63. ans += 2
  64. }
  65. l += size
  66. r -= size
  67. }
  68. if r == l-1 {
  69. return ans
  70. }
  71. return ans + 1
  72. }
  73. func same2(rank []int, rmq *RMQ, l, r, size int) bool {
  74. start1 := l
  75. start2 := r - size + 1
  76. minStart := getMin(rank[start1], rank[start2])
  77. maxStart := getMax(rank[start1], rank[start2])
  78. return rmq.Min(minStart+1, maxStart) >= size
  79. }
  80. func getMin(a, b int) int {
  81. if a < b {
  82. return a
  83. } else {
  84. return b
  85. }
  86. }
  87. func getMax(a, b int) int {
  88. if a > b {
  89. return a
  90. } else {
  91. return b
  92. }
  93. }
  94. func generateDC3(s []byte, n int) *DC3 {
  95. min0 := 2147483647
  96. max0 := -2147483648
  97. for _, cha := range s {
  98. min0 = getMin(min0, int(cha))
  99. max0 = getMax(max0, int(cha))
  100. }
  101. arr := make([]int, n)
  102. for i := 0; i < n; i++ {
  103. arr[i] = int(s[i]) - min0 + 1
  104. }
  105. return NewDC3(arr, max0-min0+1)
  106. }
  107. type DC3 struct {
  108. Sa []int
  109. Rank []int
  110. Height []int
  111. }
  112. func NewDC3(nums []int, max int) *DC3 {
  113. res := &DC3{}
  114. res.Sa = res.sa(nums, max)
  115. res.Rank = res.rank()
  116. res.Height = res.height(nums)
  117. return res
  118. }
  119. func (dc3 *DC3) sa(nums []int, max int) []int {
  120. n := len(nums)
  121. arr := make([]int, n+3)
  122. copy(arr, nums)
  123. return dc3.skew(arr, n, max)
  124. }
  125. func (dc3 *DC3) skew(nums []int, n int, K int) []int {
  126. n0 := (n + 2) / 3
  127. n1 := (n + 1) / 3
  128. n2 := n / 3
  129. n02 := n0 + n2
  130. s12 := make([]int, n02+3)
  131. sa12 := make([]int, n02+3)
  132. for i, j := 0, 0; i < n+(n0-n1); i++ {
  133. if i%3 != 0 {
  134. s12[j] = i
  135. j++
  136. }
  137. }
  138. dc3.radixPass(nums, s12, sa12, 2, n02, K)
  139. dc3.radixPass(nums, sa12, s12, 1, n02, K)
  140. dc3.radixPass(nums, s12, sa12, 0, n02, K)
  141. name := 0
  142. c0 := -1
  143. c1 := -1
  144. c2 := -1
  145. for i := 0; i < n02; i++ {
  146. if c0 != nums[sa12[i]] || c1 != nums[sa12[i]+1] || c2 != nums[sa12[i]+2] {
  147. name++
  148. c0 = nums[sa12[i]]
  149. c1 = nums[sa12[i]+1]
  150. c2 = nums[sa12[i]+2]
  151. }
  152. if sa12[i]%3 == 1 {
  153. s12[sa12[i]/3] = name
  154. } else {
  155. s12[sa12[i]/3+n0] = name
  156. }
  157. }
  158. if name < n02 {
  159. sa12 = dc3.skew(s12, n02, name)
  160. for i := 0; i < n02; i++ {
  161. s12[sa12[i]] = i + 1
  162. }
  163. } else {
  164. for i := 0; i < n02; i++ {
  165. sa12[s12[i]-1] = i
  166. }
  167. }
  168. s0 := make([]int, n0)
  169. sa0 := make([]int, n0)
  170. for i, j := 0, 0; i < n02; i++ {
  171. if sa12[i] < n0 {
  172. s0[j] = 3 * sa12[i]
  173. j++
  174. }
  175. }
  176. dc3.radixPass(nums, s0, sa0, 0, n0, K)
  177. sasa := make([]int, n)
  178. for p, t, k := 0, n0-n1, 0; k < n; k++ {
  179. i := 0
  180. if sa12[t] < n0 {
  181. i = sa12[t]*3 + 1
  182. } else {
  183. i = (sa12[t]-n0)*3 + 2
  184. }
  185. j := sa0[p]
  186. rr := false
  187. if sa12[t] < n0 {
  188. rr = dc3.leq1(nums[i], s12[sa12[t]+n0], nums[j], s12[j/3])
  189. } else {
  190. rr = dc3.leq(nums[i], nums[i+1], s12[sa12[t]-n0+1], nums[j], nums[j+1], s12[j/3+n0])
  191. }
  192. if rr {
  193. sasa[k] = i
  194. t++
  195. if t == n02 {
  196. for k++; p < n0; p, k = p+1, k+1 {
  197. sasa[k] = sa0[p]
  198. }
  199. }
  200. } else {
  201. sasa[k] = j
  202. p++
  203. if p == n0 {
  204. for k++; t < n02; t, k = t+1, k+1 {
  205. if sa12[t] < n0 {
  206. sasa[k] = sa12[t]*3 + 1
  207. } else {
  208. sasa[k] = (sa12[t]-n0)*3 + 2
  209. }
  210. }
  211. }
  212. }
  213. }
  214. return sasa
  215. }
  216. func (t *DC3) radixPass(nums []int, input []int, output []int, offset int, n int, k int) {
  217. cnt := make([]int, k+1)
  218. for i := 0; i < n; i++ {
  219. cnt[nums[input[i]+offset]]++
  220. }
  221. for i, sum := 0, 0; i < len(cnt); i++ {
  222. t := cnt[i]
  223. cnt[i] = sum
  224. sum += t
  225. }
  226. for i := 0; i < n; i++ {
  227. output[cnt[nums[input[i]+offset]]] = input[i]
  228. cnt[nums[input[i]+offset]]++
  229. }
  230. }
  231. func (t *DC3) leq1(a1 int, a2 int, b1 int, b2 int) bool {
  232. return a1 < b1 || (a1 == b1 && a2 <= b2)
  233. }
  234. func (t *DC3) leq(a1 int, a2 int, a3 int, b1 int, b2 int, b3 int) bool {
  235. return a1 < b1 || (a1 == b1 && t.leq1(a2, a3, b2, b3))
  236. }
  237. func (t *DC3) rank() []int {
  238. n := len(t.Sa)
  239. ans := make([]int, n)
  240. for i := 0; i < n; i++ {
  241. ans[t.Sa[i]] = i
  242. }
  243. return ans
  244. }
  245. func (t *DC3) height(s []int) []int {
  246. n := len(s)
  247. ans := make([]int, n)
  248. for i, k := 0, 0; i < n; i++ {
  249. if t.Rank[i] != 0 {
  250. if k > 0 {
  251. k--
  252. }
  253. j := t.Sa[t.Rank[i]-1]
  254. for i+k < n && j+k < n && s[i+k] == s[j+k] {
  255. k++
  256. }
  257. ans[t.Rank[i]] = k
  258. }
  259. }
  260. return ans
  261. }
  262. type RMQ struct {
  263. min0 [][]int
  264. }
  265. func NewRMQ(arr []int) *RMQ {
  266. res := &RMQ{}
  267. n := len(arr)
  268. k := power2(n)
  269. res.min0 = make([][]int, n+1)
  270. for i := 0; i <= n; i++ {
  271. res.min0[i] = make([]int, k+1)
  272. }
  273. for i := 1; i <= n; i++ {
  274. res.min0[i][0] = arr[i-1]
  275. }
  276. for j := 1; (1 << j) <= n; j++ {
  277. for i := 1; i+(1<<j)-1 <= n; i++ {
  278. res.min0[i][j] = getMin(res.min0[i][j-1], res.min0[i+(1<<(j-1))][j-1])
  279. }
  280. }
  281. return res
  282. }
  283. func (t *RMQ) Min(l, r int) int {
  284. l++
  285. r++
  286. k := power2(r - l + 1)
  287. return getMin(t.min0[l][k], t.min0[r-(1<<k)+1][k])
  288. }
  289. func power2(m int) int {
  290. ans := 0
  291. for (1 << ans) <= (m >> 1) {
  292. ans++
  293. }
  294. return ans
  295. }
  296. func generateS(a, b int) string {
  297. ans := make([]byte, a+b)
  298. for i := 0; i < a; i++ {
  299. ans[i] = 'a'
  300. }
  301. for i, j := a, 0; j < b; i, j = i+1, j+1 {
  302. ans[i] = 'b'
  303. }
  304. return string(ans)
  305. }
  306. func generateT(part string, n int) string {
  307. builder := strings.Builder{}
  308. for i := 0; i < n; i++ {
  309. builder.WriteString(part)
  310. }
  311. return builder.String()
  312. }
  313. func main() {
  314. fmt.Println("先展示一下DC3的用法")
  315. test := "aaabaaa"
  316. dc3 := generateDC3([]byte(test), len(test))
  317. fmt.Println("sa[i]表示字典序排名第i的是什么位置开头的后缀串")
  318. sa := dc3.Sa
  319. for i := 0; i < len(test); i++ {
  320. fmt.Printf("%d : %d\n", i, sa[i])
  321. }
  322. fmt.Println("rank[i]表示i位置开头的后缀串的字典序排多少名")
  323. rank := dc3.Rank
  324. for i := 0; i < len(test); i++ {
  325. fmt.Printf("%d : %d\n", i, rank[i])
  326. }
  327. fmt.Println("height[i]表示字典序排名i的后缀串和前一个排名的后缀串,最长公共前缀是多长")
  328. height := dc3.Height
  329. for i := 0; i < len(test); i++ {
  330. fmt.Printf("%d : %d\n", i, height[i])
  331. }
  332. fmt.Println("性能测试开始")
  333. var start, end int64
  334. s := generateS(300000, 1)
  335. t := generateT(s, 2)
  336. start = time.Now().UnixNano() / int64(time.Millisecond)
  337. fmt.Println("方法1的结果 :", longestDecomposition1(t))
  338. end = time.Now().UnixNano() / int64(time.Millisecond)
  339. fmt.Println("方法1的运行时间 :", end-start, "毫秒")
  340. start = time.Now().UnixNano() / int64(time.Millisecond)
  341. fmt.Println("方法2的结果 :", longestDecomposition2(t))
  342. end = time.Now().UnixNano() / int64(time.Millisecond)
  343. fmt.Println("方法2的运行时间 :", end-start, "毫秒")
  344. fmt.Println("性能测试结束")
  345. }

2023-08-18:用go写算法。你会得到一个字符串 text, 你应该把它分成 k 个子字符串 (subtext1, subtext2,…, subtextk)。 要求满足: subtexti 是的更多相关文章

  1. m_Orchestrate learning system---二十一、怎样写算法比较轻松

    m_Orchestrate learning system---二十一.怎样写算法比较轻松 一.总结 一句话总结:(1.写出算法步骤,这样非常有利于理清思路,这样就非常简单了 2.把问题分细,小问题用 ...

  2. 【原创】i.MXRT J-Flash烧写算法使能eFuse熔丝位写入

    ​       临近年底,终于又憋了一篇文章出来,本来年初的时候是有计划把去年总结的一些东西整理下发布出来的,结果还是被工作和生活上各种琐事给耽搁了.哎,今年刚过了自己35岁的生日,眼瞅着这个人生节点 ...

  3. arcgis api for js共享干货系列之一自写算法实现地图量算工具

    众所周知,使用arcgis api for js实现地图的量算工具功能,无非是调用arcgisserver的Geometry服务(http://localhost:6080/arcgis/rest/s ...

  4. 一步一步写算法(之prim算法 下)

    原文:一步一步写算法(之prim算法 下) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前两篇博客我们讨论了prim最小生成树的算法,熟悉 ...

  5. 一步一步写算法(之prim算法 中)

    原文:一步一步写算法(之prim算法 中) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] C)编写最小生成树,涉及创建.挑选和添加过程 MI ...

  6. 一步一步写算法(之prim算法 上)

    原文:一步一步写算法(之prim算法 上) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面我们讨论了图的创建.添加.删除和保存等问题.今 ...

  7. 一步一步写算法(之挑选最大的n个数)

    原文:一步一步写算法(之挑选最大的n个数) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 从一堆数据中挑选n个最大的数,这个问题是网上流传的 ...

  8. 一步一步写算法(之n!中末尾零的个数统计)

    原文:一步一步写算法(之n!中末尾零的个数统计) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在很多面试的题目中,求n!结果中零的个数也是 ...

  9. arcgis api 3.x for js 共享干货系列之一自写算法实现地图量算工具(附源码下载)

    0.内容概览 Geometry 地图服务方式实现地图距离以及面积的量算,简单描述 arcgis api 提供的接口类 geometryEngine 实现地图距离以及面积的量算,简单描述 自定义距离以及 ...

  10. c/c++ 通用的(泛型)算法 之 只读算法,写算法,排序算法

    通用的(泛型)算法 之 只读算法,写算法,排序算法 只读算法: 函数名 功能描述 accumulate 求容器里元素的和 equal 比较2个容器里的元素 写算法 函数名 功能描述 fill 用给定值 ...

随机推荐

  1. MySQL系列之——MySQL体系结构、基础管理(用户、权限管理、连接管理、多种启动方式介绍、初始化配置、多实例的应用)

    文章目录 一 体系结构 1.1 C/S(客户端/服务端)模型介绍 1.2 实例介绍 1.3 mysqld程序运行原理 1.3.1 mysqld程序结构 1.3.2 一条SQL语句的执行过程 1.3.2 ...

  2. win11系统无法解决的死结

    如果需要使用网上银行.win11一定不能使用. win11已经取消了,对于IE浏览器的支持和安装. 但是大部分网银都是要求IE浏览器.或者IE内核.实际过程当中.虽然所有的浏览器都说兼容IE有IE内核 ...

  3. linux特殊权限rws和rwt

    Linux文件,除了rwx这些权限外,还有一些特殊的权限,如rws.rwt. 1.s权限(setuid) 1.1 设置方法:chmod u+s 该位可以让普通用户以root用户的角色运行只有root帐 ...

  4. Java 中 extends 与implements 的区别 ?

    一.介绍extends 与 implements 的概念 1.类与类之间的继承使用extends : 子类extends父类的属性和方法,并且进行扩展或者重写. // 父类 class Animal ...

  5. Python-文件读取过程中每一行后面带一行空行。贼简单!!!!

    关键点在于,将open()函数中,参数为w的一行,格式如下: csvfile = open(data_path + '-21w.csv', 'w') 加上一个参数为newline=' ' 格式如下: ...

  6. 面向生产的 LLM 优化

    注意 : 本文同时也是 Transformers 的文档. 以 GPT3/4.Falcon 以及 LLama 为代表的大语言模型 (Large Language Model,LLM) 在处理以人为中心 ...

  7. [Python]对称日!

    def check(year): if (year%4 == 0 and year%100 != 0) or year%400 == 0: return True else: return False ...

  8. JVM-JAVA基本类型

    1 package javap.fload; 2 3 import static jdk.nashorn.internal.objects.Global.Infinity; 4 5 public cl ...

  9. CSS 溢出overflow属性的使用

    作者:WangMin 格言:努力做好自己喜欢的每一件事 在CSS中,如果给一个盒子设置了固定的宽度与高度,但内容过多就会溢出盒子本身的宽度或高度.此时,就可以使用 overflow 属性来控制内容溢出 ...

  10. 一篇文章带你了解Python常用自动化测试框架——Pytest

    一篇文章带你了解Python常用自动化测试框架--Pytest 在之前的文章里我们已经学习了Python自带测试框架UnitTest,但是UnitTest具有一定的局限性 这篇文章里我们来学习第三方框 ...