循环减法下乱序valorInicial的减数识别算法开发求助
需求说明
现有字符串变量valorInicial,仅由0-9数字组成,长度为9至60字符。从该变量中选取3个数字,分别执行循环减法(结果小于0时从9接续,例如1-3=8、0-1=9),减数仅可为-1、-2、-3,得到变量valorRestado;随后valorInicial会被打乱顺序,与valorRestado的顺序无关联。
需要开发函数,识别出valorInicial中被选中的3个数字,以及每个数字对应的减数(-1/-2/-3)。
示例
valorInicial:988735928
对9减1得8,对2减2得0,对8减3得5,得到valorRestado:858735908
频率统计:9在valorInicial中出现2次、valorRestado中1次;8均为3次;7均为1次;5在valorInicial中1次、valorRestado中2次;2在valorInicial中1次、valorRestado中0次;0在valorInicial中0次、valorRestado中1次;其余数字出现次数一致。
打乱后的valorInicial:753982898
解题思路
- 统计两个变量中各数字的出现频率
- 频率减少的数字为被减数候选,频率增加的数字为减法结果候选
- 结合仅有的三种减数,通过组合分析确定3组「被减数-减数-结果」的对应关系,需处理减法结果与原有数字重复的复杂情况
现有代码问题
提供的VBA代码仅做了基础的频率统计,缺乏深度逻辑分析,无法正确匹配每个被减数对应的具体减数(-1/-2/-3),也无法处理结果重复的复杂场景。
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click Dim valorInicial As String = "982079171" Dim restado As String = "982979978" Dim resultadoFuncion As New List(Of String) resultadoFuncion = ReconstruirValorInicial(valorInicial, restado) ' Concatenar todos los elementos de la lista en una cadena Dim mensaje As String = String.Join(vbCrLf, resultadoFuncion) ' Mostrar la cadena en un MsgBox MsgBox(mensaje, MsgBoxStyle.OkOnly, "Valores de la lista") End Sub Function ReconstruirValorInicial(valorInicial As String, restado As String) As List(Of String) Dim frecuenciaInicial As New Dictionary(Of Char, Integer) Dim frecuenciaRestado As New Dictionary(Of Char, Integer) Dim resultados As New List(Of String) ' Contar frecuencia de cada dígito For i As Integer = 0 To valorInicial.Length - 1 Dim c As Char = valorInicial.Substring(i, 1) If frecuenciaInicial.ContainsKey(c) Then frecuenciaInicial(c) += 1 Else frecuenciaInicial(c) = 1 End If Next For i As Integer = 0 To restado.Length - 1 Dim c As Char = restado.Substring(i, 1) If frecuenciaRestado.ContainsKey(c) Then frecuenciaRestado(c) += 1 Else frecuenciaRestado(c) = 1 End If Next ' Identificar dígitos restados y determinar la cantidad a restar For i As Integer = 0 To valorInicial.Length - 1 Dim c As Char = valorInicial.Substring(i, 1) Dim frecuenciaInicialDigito As Integer = frecuenciaInicial(c) Dim frecuenciaRestadoDigito As Integer = 0 If frecuenciaRestado.ContainsKey(c) Then frecuenciaRestadoDigito = frecuenciaRestado(c) End If Dim cantidadARestar As Integer If frecuenciaRestadoDigito <= frecuenciaInicialDigito Then ' Se ha restado cantidadARestar = frecuenciaInicialDigito - frecuenciaRestadoDigito End If ' Almacenar resultados If cantidadARestar > 0 Then resultados.Add(c & " : " & cantidadARestar.ToString & " (Posición: " & (i + 1).ToString & ")") End If Next Return resultados End Function
修正后的实现方案
以下是完善逻辑后的VBA函数,能够正确识别3组被减数与减数的对应关系:
Function IdentificarRestas(valorInicial As String, restado As String) As List(Of String) Dim freqIni As New Dictionary(Of Integer, Integer) Dim freqRest As New Dictionary(Of Integer, Integer) Dim resultados As New List(Of String) Dim cambios As New Dictionary(Of Integer, Integer) ' 数字: 频率变化量(restado - inicial) ' 初始化频率字典(0-9) For num As Integer = 0 To 9 freqIni(num) = 0 freqRest(num) = 0 Next ' 统计初始字符串频率 For Each c As Char In valorInicial freqIni(CInt(c.ToString)) += 1 Next ' 统计restado字符串频率 For Each c As Char In restado freqRest(CInt(c.ToString)) += 1 Next ' 计算每个数字的频率变化 For num As Integer = 0 To 9 cambios(num) = freqRest(num) - freqIni(num) Next ' 收集候选:频率减少的是被减数(变化量为负,绝对值为1) Dim candidatosRestados As New List(Of Integer) ' 收集候选:频率增加的是结果(变化量为正,绝对值为1) Dim candidatosResultados As New List(Of Integer) For num As Integer = 0 To 9 If cambios(num) = -1 Then candidatosRestados.Add(num) ElseIf cambios(num) = 1 Then candidatosResultados.Add(num) End If Next ' 遍历所有可能的减数组合(三个减数各用一次) Dim opcionesRestas As Integer() = {1, 2, 3} Dim permutaciones As New List(Of Integer()) GeneratePermutations(opcionesRestas, 0, permutaciones) For Each perm As Integer() In permutaciones Dim valido As Boolean = True Dim parejas As New Dictionary(Of Integer, Integer) ' 被减数:减数 For i As Integer = 0 To 2 Dim numRestado As Integer = candidatosRestados(i) Dim resultadoEsperado As Integer = (numRestado - perm(i) + 10) Mod 10 If Not candidatosResultados.Contains(resultadoEsperado) Then valido = False Exit For End If parejas(numRestado) = perm(i) Next ' 验证所有结果无重复 If valido Then Dim resultadosUsados As New List(Of Integer) For Each kvp In parejas Dim res As Integer = (kvp.Key - kvp.Value + 10) Mod 10 If resultadosUsados.Contains(res) Then valido = False Exit For End If resultadosUsados.Add(res) Next If valido AndAlso resultadosUsados.Count = 3 Then ' 输出匹配结果 For Each kvp In parejas resultados.Add($"被减数: {kvp.Key},减数: -{kvp.Value},结果: {(kvp.Key - kvp.Value + 10) Mod 10}") Next Return resultados End If End If Next resultados.Add("未找到有效匹配") Return resultados End Function ' 辅助函数:生成数组的全排列 Sub GeneratePermutations(ByVal arr As Integer(), ByVal index As Integer, ByRef permutations As List(Of Integer())) If index = arr.Length - 1 Then permutations.Add(arr.Clone()) Return End If For i As Integer = index To arr.Length - 1 ' 交换元素 Dim temp As Integer = arr(index) arr(index) = arr(i) arr(i) = temp GeneratePermutations(arr, index + 1, permutations) ' 回溯交换 temp = arr(index) arr(index) = arr(i) arr(i) = temp Next End Sub ' 测试调用示例 Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click Dim valorInicial As String = "753982898" ' 打乱后的初始值 Dim restado As String = "858735908" Dim resultadoFuncion As New List(Of String) resultadoFuncion = IdentificarRestas(valorInicial, restado) Dim mensaje As String = String.Join(vbCrLf, resultadoFuncion) MsgBox(mensaje, MsgBoxStyle.OkOnly, "识别结果") End Sub
代码说明
- 频率统计与变化计算:先统计两个字符串中0-9每个数字的出现次数,计算频率变化量,筛选出频率减少1的被减数候选和频率增加1的结果候选
- 全排列匹配:因为三个减数(1/2/3)各使用一次,生成所有可能的排列组合,逐一验证每个被减数减去对应减数后的循环结果是否在结果候选中
- 有效性验证:确保每个结果只被匹配一次,避免重复匹配的情况
- 循环减法处理:使用
(num - resta + 10) Mod 10实现小于0时从9接续的逻辑
内容的提问来源于stack exchange,提问作者Mencey
相关产品推荐
相关产品推荐

