ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
12
返回列表 发新帖
楼主: shaowu459

[讨论] K距离间隔重排字符串(奖励已发放)

[复制链接]

TA的精华主题

TA的得分主题

发表于 2023-12-26 16:40 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 象山海鲜 于 2023-12-26 16:53 编辑

超长超卡的来一个,未验证,如有不是最小 则需要排序
  1. =LET(n,LEN(A2),m,SEQUENCE(n),j,SORT(MID(A2,m,1)),k,UNIQUE(j),p,MAP(k,LAMBDA(x,TEXTJOIN(REPT("?",B2-1),,REPT(0,j=x)))),TAKE(TAKE(REDUCE(REPT(0,n),SEQUENCE(ROWS(k)),LAMBDA(x,y,REDUCE("",x,LAMBDA(a,b,LET(ww,INDEX(p,y),TOCOL(VSTACK(a,MAP(m,LAMBDA(c,IF(SEARCH(ww,b,c)=c,CONCAT(IF(ISERR(-MID(ww,m-c+1,1)),MID(b,m,1),INDEX(k,y))),\)))),2)))))),2),-1))
复制代码

评分

4

查看全部评分

TA的精华主题

TA的得分主题

发表于 2023-12-26 17:32 | 显示全部楼层
  1. =LET(a,LEN(A2),x,SEQUENCE(a),b,MID(A2,x,1),c,GROUPBY(b,b,COUNTA,0,0,-2),d,TAKE(c,,-1),e,TAKE(c,,1),IF(ROWS(c)=a,A2,IF(@d-1>a/B2,"",CONCAT(WRAPCOLS(MID(CONCAT(REPT(e,d-(d=@d))),x,1),@d-1,""),FILTER(e,d=@d)))))
复制代码

评分

3

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-12-27 21:51 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
结贴。本题参与朋友不算多,主要统计自己、剑指E、alan的公式(都是完成基础题目要求的公式)。11楼公式对随机数据验证卡,比较难验证,能达到基础题目要求,但没有达到字典序最小。9楼、12楼公式在某些情况下有bug,未统计在内。

图片.png

参与者均发放50财富值,剑指E发放1技术分。


K距离间隔重排字符串-公式汇总.rar

20.07 KB, 下载次数: 3

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-12-27 22:19 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
简单说明一下我的公式思路,有兴趣的朋友可以继续就细节探讨。

解决这个问题有两个核心点:1)假设字符串按k可以分成n组,如果有某个字母重复次数超过n是不可能重排后满足要求的;2)如果以一个空数组存储重排后的字母时,每次应优先放入剩余字母中出现次数最多的,这样才能保证字母尽可能分散在不同的组中,否则即使原字符串可以重排为满足要求的字符串也可能出现将相同的字母挤压到某一个分组中的情况。重排的时候,如果字母没有在结果数组中出现过,就可以尽量往前摆放,如果字母已经出现过,则可放在该字母最后出现位置+k的位置。

公式简要说明如下:
=LET(
    h, LEN(A2),    获取字符串长度
    r, SEQUENCE(h),    生成1~字符串长度的序列
    s, MID(A2, r, 1),    提取字符串中的每个字符
    IFERROR(          如果公式返回错误值,也就是在摆放某个字母时,对应位置已经超过原字符串长度的时候
        CONCAT(
            REDUCE(
                r * 0,    生成一个全是0的数组,行数和字符串长度一样,用于存储结果
                SORTBY(s, -MAP(s, r, LAMBDA(m, n, SUM(N(TAKE(s, n) = m))))),    按每个字母从上到下出现的次数排列,上面字母的数量要大于等于下面字母的数量
                LAMBDA(x, y,
                    LET(
                        p, MATCH(, x, ),     获取结果数组中第一个0的位置
                        k, XMATCH(y, x, , -1) + B2,   获取当前遍历的字符在x中的位置然后加上k,作为当前字符可以存放的位置(假设在结果数组中已经出现过当前字符)
                        IF(
                            r =      判断位置,更新结果数组中的值
                                IFS(
                                    ISNA(k),   如果当前字符在结果数组x中没有出现过,
                                    p,         则将当前字符插入在x中第一个0出现的位置
                                    k > h,     如果要插入的字符位置y已经超过了字符串的长度(无法保证无重的放入)
                                    \,         则返回错误值
                                    INDEX(x, k) > 0,     如果要插入的位置已经有字母填充了
                                    p,         则仍插入在结果数组x中第一个0的位置
                                    1,         其他情况,
                                    k          将当前遍历字母插入在字母上次出现位置+k的位置
                                ),
                            y,    如果1~n的序列等于上述位置,则将结果数组中的对应位置更新为当前遍历的字母
                            x     否则仍然保留x不变
                        )
                    )
                )
            )
        ),
        ""    出现错误值时返回空,也即当前字母已经无法无重的插入结果数组的时候
    )
)

评分

2

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-12-27 22:30 | 显示全部楼层
另外一个公式简要说明如下:

=LET(
    s, MID(A2, ROW($1:200), 1),     提取字符串中的每个字符,并获取多个空文本
    t, @REDUCE(
        UNIQUE(HSTACK(s, MAP(s, LAMBDA(x, SUM(N(s = x)))))),    统计s中的每个字符出现次数并和字符合并成一个数组后去重,作为x的初始值
        s,    循环足够多的次数
        LAMBDA(x, y,
            LET(
                d, SORT(x, 2, -1),    按x第二列排序,此时空字符串次数最多,每次循环时都在第一行。剩余字符数量多的位置更高。
                p, DROP(d, 1, -1),    获取当前循环时剩余尚未使用的字母(不重复值列表)
                r, ROWS(p),           获取尚未使用字母的个数
                v, DROP(d, 1, 1) - (SEQUENCE(r) <= B2),   每次提取出前k个字母填充入结果数组,也就是使用了一次,因此对应次数-1,但只有前k个-1,其余字母次数保持不变
                IF(
                    OR(x = 0),        类似设定退出条件,当x中有0的时候,保持x不变。
                    x,
                    VSTACK(
                        TAKE(d, 1) & CONCAT(TAKE(p, B2)),   用第一行合并当前提取的前k个可以使用的字母
                        FILTER(HSTACK(p, v), v * (r >= B2), {0, 0})   筛选剩余次数大于0的字母,如果筛选不到结果就返回{0,0}的数组。注意,如果剩余可使用的字母小于k个,则一次性合并进结果,次数清0。因为下次再提取合并进结果字符串的话,已经无法保证相同字母之间距离不小于k了。
                    )
                )
            )
        )
    ),
    REPT(t, LEN(t) = LEN(A2))    如果结果字符串等于源字符串长度则返回结果字符串,否则返回空值。
)

评分

2

查看全部评分

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-22 00:33 , Processed in 0.032201 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表