了解Count Triplets HackerRank

时间:2019-09-22 10:49:06

标签: arrays python-3.x

我一直在努力应对这一挑战:Count Triplets,经过大量的努力,我的算法并未在每个测试用例中都可以解决。

由于在讨论中,我看到了一个代码并试图找出该代码的真正功能,所以我仍然无法理解该代码是如何工作的。

解决方案:

from collections import defaultdict

arr = [1,3,9,9,27,81]
r = 3
v2 = defaultdict(int)
v3 = defaultdict(int)
count = 0
for k in arr:
    count += v3[k]
    v3[k*r] += v2[k]
    v2[k*r] += 1
print(count)

上面的代码完美地适用于每个测试用例。我已经测试了kv2v3的值,以了解但仍然不了解代码如何在计数三胞胎时如此平稳。我也梦in以求的解决方案。我想知道人们如何聪明地制定出这种解决方案。不过,如果能得到适当的解释,我将感到高兴。谢谢

k,v2,v3的输出

from collections import defaultdict

arr = [1,3,9,9,27,81]
r = 3
v2 = defaultdict(int)
v3 = defaultdict(int)
count = 0
for k in arr:
    count += v3[k]
    v3[k*r] += v2[k]
    v2[k*r] += 1
    print(k, count, v2, v3)

输出

1 0 defaultdict(<class 'int'>, {1: 0, 3: 1}) defaultdict(<class 'int'>, {1: 0, 3: 0})                                                  
3 0 defaultdict(<class 'int'>, {1: 0, 3: 1, 9: 1}) defaultdict(<class 'int'>, {1: 0, 3: 0, 9: 1})                                      
9 1 defaultdict(<class 'int'>, {27: 1, 1: 0, 3: 1, 9: 1}) defaultdict(<class 'int'>, {27: 1, 1: 0, 3: 0, 9: 1})                        
9 2 defaultdict(<class 'int'>, {27: 2, 1: 0, 3: 1, 9: 1}) defaultdict(<class 'int'>, {27: 2, 1: 0, 3: 0, 9: 1})                        
27 4 defaultdict(<class 'int'>, {27: 2, 1: 0, 3: 1, 81: 1, 9: 1}) defaultdict(<class 'int'>, {27: 2, 1: 0, 3: 0, 81: 2, 9: 1})         
81 6 defaultdict(<class 'int'>, {1: 0, 3: 1, 243: 1, 81: 1, 9: 1, 27: 2}) defaultdict(<class 'int'>, {1: 0, 3: 0, 243: 1, 81: 2, 9: 1, 
27: 2})

4 个答案:

答案 0 :(得分:1)

因此,代码在遍历数组时正在跟踪潜在的对和三元组。

For each value in the array:
    // Increment count by the number of triplets that end with k
    count += v3[k]
    // Increment the number of potential triplets that will end with k*r
    v3[k*r] += v2[k]
    // Increment the number of potential pairs that end with k*r
    v2[k*r] += 1  

任何给定k的三元组数是到目前为止我们遇到的任何给定k / r的对数。 请注意,在整个循环中,v3 [k]和v2 [k]通常会为零,直到它们达到上一次迭代的预测k * r值为止。

答案 1 :(得分:1)

1。问题

该函数有两个参数,即:

  • arr:整数数组
  • r:一个整数,公共比率

因此,输入内容可能类似于

arr: [1, 2, 2, 4]
r: 2

目标是返回形成几何级数的三元组的数量。


2。解决方法

要解决此问题,有多种方法。例如,根据SagunB

comment from RobertsN
  • 可以在O(n)->单次通过数据中完成
  • 不需要除法,只需要乘以R即可
  • 必须使用map(C ++)或dict(Java,Python)->可以是无序映射(节省O(logN))
  • 在读取值时尝试思考->以后该值会成为三元组的一部分吗?
  • 无需考虑(R == 1)作为极端情况
from collections import Counter

# Complete the countTriplets function below.
def countTriplets(arr, r):
    r2 = Counter()
    r3 = Counter()
    count = 0
    
    for v in arr:
        if v in r3:
            count += r3[v]
        
        if v in r2:
            r3[v*r] += r2[v]
        
        r2[v*r] += 1

    return count

或者就像你说的

from collections import defaultdict

# Complete the countTriplets function below.
def countTriplets(arr, r):
    v2 = defaultdict(int)
    v3 = defaultdict(int)
    count = 0
    for k in arr:
        count += v3[k]
        v3[k*r] += v2[k]
        v2[k*r] += 1
    return count

3。最终结果

两个案例都将通过HackerRank中的所有13个测试案例

It works


4。您的情况说明

RobertsN的评论在很大程度上解释了您的代码(与您的代码非常相似)。尽管如此,为了更好地了解代码的工作原理,只需打印v2和v3的计数即可。

假设您将输入

4 2
1 2 2 4

预期输出是

2

此外,我们知道definition的v2和v3都将看起来像

defaultdict(<class 'int'>, {})

留下了for循环需要理解。可能引起混淆的是运算符+ =,但这是already addressed by me in another answer

因此,现在要了解其余内容,我们可以将循环更改为

for k in arr:
    print(f"Looping...")
    print(f"k: {k}")
    print(f"v3_before_count: {v3}")
    count += v3[k]
    print(f"count: {count}")
    print(f"k*r: {k*r}")
    print(f"v3_before: {v3}")
    v3[k*r] += v2[k]
    print(f"v3[k*r]: {v3[k*r]}")
    print(f"v2[k]: {v2[k]}")
    print(f"v3_after: {v3}")
    print(f"v2_before: {v2}")
    v2[k*r] += 1
    print(f"v2_after: {v2}")
    print(f"v2[k*r]: {v2[k*r]}")

将允许您查看

Looping...
k: 1
v3_before_count: defaultdict(<class 'int'>, {})
count: 0
k*r: 2
v3_before: defaultdict(<class 'int'>, {1: 0})
v2_before_v3: defaultdict(<class 'int'>, {1: 0})
v3[k*r]: 0
v2[k]: 0
v3_after: defaultdict(<class 'int'>, {1: 0, 2: 0})
v2_before: defaultdict(<class 'int'>, {1: 0})
v2_after: defaultdict(<class 'int'>, {1: 0, 2: 1})
v2[k*r]: 1
Looping...
k: 2
v3_before_count: defaultdict(<class 'int'>, {1: 0, 2: 0})
count: 0
k*r: 4
v3_before: defaultdict(<class 'int'>, {1: 0, 2: 0})
v2_before_v3: defaultdict(<class 'int'>, {1: 0, 2: 0})
v3[k*r]: 1
v2[k]: 1
v3_after: defaultdict(<class 'int'>, {1: 0, 2: 0, 4: 1})
v2_before: defaultdict(<class 'int'>, {1: 0, 2: 1})
v2_after: defaultdict(<class 'int'>, {1: 0, 2: 1, 4: 1})
v2[k*r]: 1
Looping...
k: 2
v3_before_count: defaultdict(<class 'int'>, {1: 0, 2: 0, 4: 1})
count: 0
k*r: 4
v3_before: defaultdict(<class 'int'>, {1: 0, 2: 0, 4: 1})
v2_before_v3: defaultdict(<class 'int'>, {1: 0, 2: 0, 4: 1})
v3[k*r]: 2
v2[k]: 1
v3_after: defaultdict(<class 'int'>, {1: 0, 2: 0, 4: 2})
v2_before: defaultdict(<class 'int'>, {1: 0, 2: 1, 4: 1})
v2_after: defaultdict(<class 'int'>, {1: 0, 2: 1, 4: 2})
v2[k*r]: 2
Looping...
k: 4
v3_before_count: defaultdict(<class 'int'>, {1: 0, 2: 0, 4: 2})
count: 2
k*r: 8
v3_before: defaultdict(<class 'int'>, {1: 0, 2: 0, 4: 2})
v2_before_v3: defaultdict(<class 'int'>, {1: 0, 2: 0, 4: 2})
v3[k*r]: 2
v2[k]: 2
v3_after: defaultdict(<class 'int'>, {1: 0, 2: 0, 4: 2, 8: 2})
v2_before: defaultdict(<class 'int'>, {1: 0, 2: 1, 4: 2})
v2_after: defaultdict(<class 'int'>, {1: 0, 2: 1, 4: 2, 8: 1})
v2[k*r]: 1

并提取所需的疾病。从中我们可以观察到什么?

  • 计数在最后一个循环中从0增加到2。
  • k遍历了所有的arr值-因此它将是1、2、2和4。
  • 在初始循环中,v3_before_count为{},而v3_before为{1:0}

此过程很可能会引发问题,回答这些问题会使您更加了解它。

答案 2 :(得分:1)

我一直试图理解它,最后,这个 C# 代码应该很清楚

static long countTriplets(List<long> arr, long r)
{
    //number of times we encounter key*r
    var doubles = new Dictionary<long, long>();
    //number of times we encounter a triplet
    var triplets = new Dictionary<long, long>();
    long count = 0;
    foreach (var key in arr)
    {
        long keyXr = key * r;

        if (triplets.ContainsKey(key))
            count += triplets[key];

        if (doubles.ContainsKey(key))
        {
            if (triplets.ContainsKey(keyXr))
                triplets[keyXr] += doubles[key];
            else
                triplets.Add(keyXr, doubles[key]);
        }

        if (doubles.ContainsKey(keyXr))
            doubles[keyXr]++;
        else
            doubles.Add(keyXr, 1);
    }
    return count;
}

答案 3 :(得分:0)

from collections import defaultdict

arr = [1,3,9,9,27,81]
r = 3
v2 = defaultdict(int)   #if miss get 0
v3 = defaultdict(int)   #if miss get 0 
count = 0`enter code here`
for k in arr:
    #updating the count, starts propagating with delay=2 elements
    count += v3[k]

    # number of triplets with last component ending
    # on index i of k in array
    v3[k*r] += v2[k]

    # number of pairs with last component ending
    # on index i of k in array
    v2[k*r] += 1
print(count)

最好通过示例来理解 - 假设我们有数组 11111, 我们在 i=3 上,所以 111>1<1.

v2 当前计数为 111, 11>1< 有两对以 >1< 结尾,通常 n-1 表示 length(array)=n。

现在在 v3 我们从 v2 递归构造计数,如下所示:对于用 v2 创建和计数的每一对,我们分配最后一个组件有 n 个这样的选项 对于#pairs = n。

所以对于 i=3:

11.1 (v2=1) //this pair remains by sum
+
.111 (v2=2) //these are new
1.11 (v2=2)

希望这会有所帮助!