【问题标题】:What is the correct algorithm to return all combination of elements where i<j<k返回 i<j<k 的所有元素组合的正确算法是什么
【发布时间】:2022-01-21 05:55:54
【问题描述】:

我必须找到数组 a[] 中索引为 i,j,k 的所有组合,使得 i

我尝试了递归方式并将所有组合存储在一个集合中,这样如果我再次访问相同的组合,我只会通过从集合中检查它来从那里返回

我的代码是这样的,但我正在为大型案例获得 TLE 谁能给我最有效的方法

 static Set<String> set = new HashSet<>();
 static int sum = 0;

    static void solve(int i,int j,int k,int[] a){
        if(i>=j || j>=k ||k>=a.length){
            return;
        }
        
        //combination
        String pre = String.valueOf(i)+String.valueOf(j)+String.valueOf(k);
        if(set.contains(pre)){
            return;
        }

        //operation to perform for every combination
        int v = (a[i] | a[j] | a[k]) ^ (a[i] ^ a[j] ^ a[k]);
        sum = sum+v;

        solve(i,j,k+1,a);
        solve(i,j+1,k,a);
        solve(i+1,j,k,a);
    }

【问题讨论】:

    标签: java algorithm recursion data-structures dynamic-programming


    【解决方案1】:

    对于三个索引,创建三个循环更简单。为了简单起见,我还添加了两个二进制操作的预计算并删除了集合检查。

    static int solve(int[] a){
        int leng = a.length;
        int sum = 0;
        for (i=0; i < leng-2; i++)   {
           for (j=i+1; j < leng - 1; j++)   {
               int ijor = a[i] | a[j];
               int ijxor = a[i] ^ a[j];
               for (k=j+1; k < leng; k++)   {
                  //operation to perform for every combination
                 sum = sum + (ijor | a[k]) ^ (ijxor ^ a[k]);
               }
            }
         }
         return sum; 
    }
    

    【讨论】:

    • 但这是一个蛮力解决方案,这不会给我 n3 的时间复杂度
    • 是的,但是你没有解释真正的问题,只是写了你的函数
    • 好吧抱歉,实际上我必须返回给定条件下所有不同组合给出的操作总和i
    【解决方案2】:

    我看到您使用的是 java,但是,我可以使用 python 提供答案,但我确信 java 中也有等效的操作:

    from itertools import combinations
    def combs_tri(X):
        lenght=len(X)
        num_of_zeros=lenght-3
        def factorial(n):
            m=1
            for x in range(1,n+1):
                m=m*x
            return m
        def num_of_comb(n,z):
            return int(factorial(lenght)/(factorial(z)*factorial(lenght-z)))
        count=num_of_comb(lenght,3)
        def create_boolean_array(num_of_zeros,count,lenght):
            Arr=np.zeros((count,lenght))
            combs=list(combinations(range(lenght), 3))
            for i,comb in enumerate(combs):
                Arr[i,comb]=1
            return Arr
        repeated_list=np.repeat([X],count,axis=0)
        bool_mask=create_boolean_array(num_of_zeros,count,lenght)
        return repeated_list[bool_mask.astype(bool)].reshape((int(count)),3)
    

    功能说明

    factorial:执行 n!=n(n-1)(n-2)...

    的数学运算阶乘

    num_of_comb:执行数学组合运算,返回数值结果。

    create_boolean_array:创建一个布尔掩码以获取数组元素的所有可能组合。 ->combinations():返回组合 例如/组合([1,2,3],2)=[(1,2),(1,3),(2,3)]

    ->np.repeat([X],count,axis=0) 按给定计数重复给定列表。计数表示此处的组合数(3)。

    Ex/ np.repeat([1,2,3,4],count,axis=0)=np.array([[1,2,3,4],[1,2,3,4] ,[1,2,3,4],[1,2,3,4]])


    在大多数情况下,数组操作比 for 循环快得多。

    【讨论】:

    • 你好 Hakan,你能解释一下你的代码,就像你的方法一样,哪些函数在做什么。真的很有帮助
    • 我已经试着解释过了,但是如果你有更多的问题,你可以再问一遍
    • 我还有一些疑问,为什么你计算阶乘它的重要性是什么,我不明白 num_of_comb 函数的工作原理以及这将如何帮助?然后在 create_boolean_array 函数中 np, np.zeros 是什么。 ?就像我想知道这个解决方案背后的主要概念和思考一样谢谢
    • np.zeros 创建一个零数组,例如 np.zeros(4,4) 创建一个用 0 填充的 4,4 数组。通过将一些索引更改为 1,我们可以使用布尔逻辑。 0s 表示假,1 表示真。在 python 的 numpy 库中,通过使用布尔逻辑,您可以提取只有 true 的元素,因此为 1s。需要 num_of_comb 才能知道给定列表必须重复多少次(在 repeat_list 部分中使用),在布尔数组创建中也需要它。
    • 主要概念是通过重复创建给定列表的数组。想象一个给定的列表是一行,它重复的组合数量与列号的数量一样多。通过使用布尔逻辑获得这样的数组后,您可以提取可能的组合,并创建一个由 0 和 1 组成的数组。作为示例给出的列表是 [1,2,3,4] repated_list 是 [[1,2,3,4] ,[1,2,3,4] ,[1,2,3,4] ,[1 ,2,3,4] ],布尔掩码为 [[0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1, 0]]。正如你所看到的,当我们使用掩码时,我们有 [[2,3,4],[1,3,4],[1,2,4],[1,2,3]]。所以这就是这个想法背后的本质。我希望它很清楚
    【解决方案3】:

    我认为这是一个非常简单的问题,只有 3 个循环。我用c++写过代码,但你一定会明白的:

    #include <vector>
    #include <iostream>
    
    void print_all(const std::vector<int>& arr){
        for (size_t i = 0; i < arr.size() - 2; i++) {
            for (size_t j = i + 1; j < arr.size() - 1; j++) {
                for (size_t k= j + 1; k < arr.size(); k++) {
                    if ((arr[i] < arr[j]) || (arr[i] > arr[j] && arr[i] < arr[k]))
                        std::cout << "[" << arr[i] << "," << arr[j] << "," << arr[k] << "]\n";
                }
            }
        }
    }
    
    int main() {
        std::vector<int> arr = {12, 1, 34, 32};
        print_all(arr);
    }
    

    对于条件,对于一个元组(a, b, b)

    1. 如果a&lt;b,那么您可以选择任意c,最多移动1 次即可到达a&lt;b&lt;c
    2. 如果a&gt;b需要切换,那么所有c都需要大于a

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-23
      相关资源
      最近更新 更多