问题:数字元素均匀分布

6 篇文章 0 订阅
5 篇文章 0 订阅

20210619_数字元素均匀分配

前言

在工作中,有位同事提出了一个场景问题,当时没有只想到前两种方法,事后发现还有2种方法,所以进行笔记

时间线

2021年6月18日 问题提出,解决

2021年6月19日 笔记

问题

从1到n存在若干数字元素,如何将这些数字元素均匀分配到k个集合中。

例如从1到32,将元素分到8个集合中,则8个集合中的第1个集合是[1,9,17,25],第2个集合是[2,10,18,26]

解决思路

思考

可以使用数据结构实现问题场景模拟,也可以使用数学方法

方法1:使用队列

最开始时想到的便是使用队列模拟实现

在一个集合中创建x个空子集合,遍历1到n,每一次都将集合弹出头部子集合,插入当前元素后,再将这个子集合从集合的尾部插入。

遍历所有元素后,即完成。

4个元素分为2组进行模拟,有如下结果:

遍历元素(从1到4)结果
开始[[],[]]
1[[],[1]]
2[[1],[2]]
3[[2],[1,3]]
4[[1,3],[2,4]]
结束[[1,3],[2,4]]

方法2:使用栈

问题中,还有一些信息是可以使用到的,如下:

  1. 有n个元素,分为k组,在整除的条件下,每一组会有n//k个元素
  2. 第1组的子集合中的第1个元素是1,第2个元素是1+k,依次类推,共有n//k个元素,表达式可以如下:

x = 1 + ( n − 1 ) k x = 1+(n-1)k x=1+(n1)k

  1. 如果知道第1组的结果后,可以求出后面几组的结果,需要通过k-1次求解可以得到结果

通过以上结论,使用栈很容易实现。

同上,使用4个元素分为2组进行模拟:

过程

  • 开始时,结果集合为[],

  • 求出第1个子集合,可以得到 [[1,3]]

  • 获取集合尾部的第一个子集合,根据子集合中的结果,逐个加1,可得到另一个子集合,再从集合尾部插入

  • 重复上一步骤k-1次后结束

方法3:等差数列

前面两个都是使用的场景模拟,利用了大部分条件,如多少个元素,分为多少组,怎么分配才能保证场景实现等等,

但没有具体到数学公式中。而问题中,有两个重要变量,即第几个子集合,在子集合中的第几个位置。

以上两个变量是前提

通过观察,可以发现,

集合角度考虑,集合中有k个子集合。第k个子集合中的第一个元素是k,如第1个子集合的第一个元素是1,第2个子集合的第1个元素是2,依次类推

子集合角度考虑,子集合中有n//k个元素,每一个子集合是一个等差数列

而根据等差数列表达式有:
a n = a 1 + ( n − 1 ) d a_n = a_1 + (n-1)d an=a1+n1d
其中a1表示子集合中的第1个元素,d为k,而n表示子集合中第几个元素,

使用i和j分别表示第几个子集合,在子集合中的第几个位置,会有:
x = i + ( j − 1 ) ∗ k x = i + (j-1)*k x=i+(j1)k
使用4个元素分为2组进行模拟,则第2个子集合中的第2个元素,为x=2+(2-1)*2=4

方法4:求余

使用队列和栈需要大量的弹出插入操作,而等差数列的实现需要双重for循环,虽然两层for循环的次数为n。

而集合中的定位是可以通过求余获得的。集合中的第1个子集合中的元素与k相除,会余下1

第2个子集合中的元素与k相除,会余下2,依次类推

到了最后一个子集合,由于刚好是第k组,会整除。

所以使用求余是可行的。

代码实现

class Solution:
    def splitOfQueue(self,k,n):
        if n%k != 0:
            return
        res = [[] for i in range(k)]
        for i in range(n):
            topList = res.pop(0)
            topList.append(i+1)
            res.append(topList)
        return res
    def splitOfStack(self,k,n):
        if n%k != 0:
            return
        nums = n // k
        res = [[1+i*k  for i in range(nums)]]
        for i in range(1,k):
            ele = [ele+1 for ele in res[-1]]
            res.append(ele)
        return res
    def splitOfAS(self,k,n):
        if n%k != 0:
            return
        nums = n // k
        res = []
        for i in range(k):
            ele = []
            for j in range(nums):
                ele.append(i+1+j*k)
            res.append(ele)
        return res
    def splitOfComp(self,k,n):
        if n%k != 0:
            return
        res = [[] for i in range(k)]
        for i in range(n):
            res[i%k].append(i+1)
        return res
if __name__ == "__main__":
    sol = Solution()
    res = sol.splitOfStack(8,32)
    res = sol.splitOfAS(8,32)
    res = sol.splitOfComp(8,32)
    res = sol.splitOfQueue(8,32)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值