Lab03 Longest-duplicate-substring
Purpose
子字符串是字符串中至少出现一次的连续字符序列。重复子字符串是一种由相同字符组成的子字符串。例如,“aabbbc”的重复子字符串是“aa”,“bbb”和“c”。
给定一个字符串及其长度,计算出它最长的重复子字符串的长度。
condition:
请注意,(1<=N<=100) 将存储在 x3100 中,并且 的每个字符都存储在从地址 x3101 开始的连续内存位置。
您可以假设仅包含 a-z 和 A-Z。
任务:将输出、最长的重复子字符串存储在 x3050 中。
R0-R7 初始设置为零,程序应从 x3000 开始。
several examples:
Memory address | x3050 | x3100 | x3101 | x3102 | x3103 | x3104 | x3105 | x3106 |
---|---|---|---|---|---|---|---|---|
example 1 | RESULT=3 | NUM=6 | a | a | b | b | b | c |
example 2 | RESULT=4 | NUM=5 | Z | Z | Z | Z | z | |
example 3 | RESULT=3 | NUM=6 | a | a | b | a | a | a |
Principles
Key issues:
如何记录最长重复的数量
要记录最长的重复数量,我们对字符串进行分析,可以看出,任意一个字符串,我们取其具有连续相同子串的模式,在任一时刻可以看作三部分,如xxxyzzz、xxxyzyzwww等,即两部分连续重复子串间隔一部分不连续的子串,即任意时刻我们最多只需要两个变量分别保存最长长度以及当前统计的连续重复子串长度,当这个相同连续被打破即出现不同字符时,比较一下两个长度,取其较大值。所以统计相同字符数量时使用两个寄存器:R2,R3,R2记录最长长度,R3记录当前子串相同字符长度,当判断到不同字符时,R3停止记录,跳转至比较R2与R3的大小,取其较大值存至R3中,并将R3清零后继续向后读取字符串,直至结束。
如何判断两个字符是否相同
在使用其他高级语言编程统计重复字符时,通常会用到双指针进行记录,所以联系到汇编语言,我们可以使用两个寄存器R5、R6作为两个指针,初始时分别指向第一个字符和第二个字符,每次判断是否满足R5==R6,满足则当前长度+1并后移指针,否则说明两个字符不相同,当前长度不变并将指针后移,直至R6指向最后一个字符,程序也相应结束。
Flow chart:
Procedure
初始化:R0存放字符串总长度,因为使用双指针比较字符,所以R0=R0-2作为循环的总次数,R1存放字符串的起始地址,R2,R3分别存放最大长度和当前长度,R5,R6分别记录前一个字符和后一个字符,作为双指针向前移动
循环:将R5与R6相减用于比较当前两个字符是否相等,相等则R3+1,不相等则跳转比较,令R2=max(R2,R3),再回到循环,判断循环计数R0是否满足R0>0,满足则R1+1,R5,R6对应+1,即向前读入一个字符进行比较,重复循环过程。
结束:R0<0时跳转至存储,存储之前需要再做一次R2与R3的比较,将最大值放入R2中,最后将R2的值存入x3050内存单元
Result
Debug:
过程中遇到的主要问题有:
对于下列两个样例
89:sdsdsdssssssssdsdsfdjkkkkkkkkkkdlslsjdfnnnnnsdswiejdjskjsfkdsfdfskdksknsnsjsndllbbbbbdfsd:10
92:sdsdsdssssssssdsdsfdjkkkkkkkkkkdlslsjdfnnnnnsdswiejdjskjsfkdsfdfskdksknsnsjsndllbbbbbdfsdddd:10
分别输出10 以及 13,结果如下图所示,两个样例最长的子串都应该是连续的10个k,两个样例的区别仅在于最后的ddd,然而输出结果却不同
在调试模式中发现,在处理最后的子串时R3由8变为9后,遇到了不同的子串却没有清零,而是继续增加,即由9到10
检查发现代码中对R3的清零操作仅当R2<R3时才进行清零,所以上述情况就是在特殊情况下R2==R3,但未正确清零R3,导致R3继续计数输出错误结果
所以上述代码应改为如下图所示:
并且,由于我的程序是通过检测到不同字符时,跳转至比较当前R3正在记录的长度与R2中记录的最长长度并取最大值存入R2中,所以在程序要结束时应该再比较一次,因为可能存最后结尾的子串是最长的重复子串的情况。
Judge:
在本地 LC3Tool \text{LC3Tool} LC3Tool调试完毕后,将代码整理如下:用于网站在线 lc3 \text{lc3} lc3评测
.ORIG x3000
LDI R0, NUM;
ADD R0, R0, #-2;循环次数
LD R1, DATA ; R1 is the pointer of the string
ADD R2, R2, #0;计数器
ADD R3, R3, #0;
CHECK LDR R5, R1, #0;第一个字符
LDR R6, R1, #1;第二个字符
NOT R5, R5;
ADD R5, R5, #1;R5取反
ADD R5, R5, R6;相加为0说明相同
BRz CNT ;
BRnp CMP ;
CNT ADD R3, R3, #1 ;计数
LOOP ADD R0, R0, #-1 ;循环次数
BRn BREAK ;结束
ADD R1, R1, #1 ;后移
BR CHECK
CMP NOT R4, R3;
ADD R4, R4, #1 ;R3取反
ADD R4, R2, R4 ;
BRnz MAX ;R2<R3
AND R3, R3, #0 ;R3<-0
BR LOOP ;
MAX ADD R2, R3, #0 ;R2=R3
AND R3, R3, #0 ;R3<-0
BR LOOP;
BREAK
ADD R7, R0, #1 ;循环次数
BRz CMP;
ADD R2, R2, #1;
STI R2, RESULT
HALT
RESULT .FILL x3050
NUM .FILL x3100
DATA .FILL x3101
.END
评测结果如下,正常运行,输出正确。