【问题标题】:restore the 0-1 matrix based on the row sums and column sums根据行和列和恢复0-1矩阵
【发布时间】:2020-02-29 02:22:47
【问题描述】:

请注意: 这个问题很长,可能需要一些时间阅读:

我在编码测试中遇到了这个问题:

假设我们有一个 2 行 N 列的 0-1 矩阵,假设 U=the 上排之和,L=下排之和,int[] C=数组 包含每列的总和,返回字符串表示 矩阵。如果有多个,则返回其中任何一个。如果不 矩阵满足,返回“IMPOSSIBLE”。

例子1:

U=3,L=2,C=[2,1,1,0,1] return String="11100,10001"(两行是 用“,”分隔)

我通过以下方法得到了 50% 的正确率和 14% 的速度:

我的想法:

  1. 如果 U+L != C 中元素的总和,则返回“IMPOSSIBLE”;
  2. 否则,用 0 初始化矩阵,并使用 for 循环访问 C 中的每个元素:
    如果 C[i]==2,则将每行中的元素设置为 1;
    if C[i]==0 将每行中的元素设置为 0;
    如果 C[i]==1 && 0 否则,将上排元素设置为 0,将下排元素设置为 1;
  3. 最后我们访问矩阵中的每个元素,得到结果 String(with StringBuilder.append())。

谁能帮我改进它? 经过长时间的思考,我无法找到更好的解决方案。 我认为这个解决方案应该是 100% 正确的,O(N) 应该是最小时间复杂度,其中N 是矩阵元素的总数。


----更新:

class Solution {
public String solution(int U, int L, int[] C) {
    // write your code in Java SE 8
    int N=C.length;

    int colSum=0;
    for(int i=0;i<N;i++){
        colSum+=C[i];
    }
    if(colSum!=U+L){
        return "IMPOSSIBLE";
    }


    String[] upRow=new String[N];
    String[] lowRow=new String[N];
    for(int i=0;i<N;i++){
        if(C[i]==2){
            upRow[i]="1";
            lowRow[i]="1";
            U--;
            L--;
        }else if(C[i]==0){
            upRow[i]="0";
            lowRow[i]="0";
        }else{
            if(0<U){
                upRow[i]="1";
                lowRow[i]="0";
                U--;
            }else{
                upRow[i]="0";
                lowRow[i]="1";       
            }           
        }
    }

    StringBuilder sb=new StringBuilder();
    for(int i=0;i<N;i++){
        sb.append(upRow[i]);
    }
    sb.append(",");
    for(int i=0;i<N;i++){
        sb.append(lowRow[i]);
    }
    return sb.toString();
}

}

【问题讨论】:

  • 如果你有 U=2 L=0 C=[2] 你的算法将返回 1,1 而不是认识到这是不可能的,这只是一个例子。至于速度14%我不知道是什么意思,是怎么计算的?发布您的代码。
  • @Oleg 这可以通过在字符串构造后检查矩阵是否满足标准来缓解。 (可能应该表示为一个数组以便于求和)
  • @Oleg 你是对的。如果 U 或 L 大于 C 中的非零元素计数,则它是不可能的。
  • @Oleg 我也不知道那 14%。我想这意味着只有 14% 的测试用例可以在时间限制内产生结果。
  • @Arch2K 我发布了一个基于 cmets 的解决方案,用不同的输入进行了测试,似乎可行。

标签: java algorithm


【解决方案1】:

基于cmets的解决方案:

public static String check(int[] c, int u, int l) {
    // decrease the sum of upper and lower rows by the number of sum 2 columns
    int twos = (int) Arrays.stream(c).filter(a -> a == 2).count();
    u -= twos;
    l -= twos;

    StringBuilder upper = new StringBuilder();
    StringBuilder lower = new StringBuilder();

    for (int a : c) {
        switch (a) {
        // sum was already decreased, just add 1 to each row
        case 2: 
            upper.append('1');
            lower.append('1');
            break;
        // first put 1 in the upper row and decrease it's sum until it reaches 0 then switch to lower row
        case 1: 
            if (u > 0) {
                upper.append('1');
                lower.append('0');
                u--;
            } else {
                upper.append('0');
                lower.append('1');
                l--;
            }
            break;
        case 0:
            upper.append('0');
            lower.append('0');
        }
    }

    // if and only if the sum of both rows is now 0 a solution was found otherwise return "IMPOSSIBLE"
    return u == 0 && l == 0 ? upper.toString() + "," + lower.toString() : "IMPOSSIBLE";
}

如果ul小于0,可以在到达终点之前知道没有解决方案,例如可以在代码中添加检查:

if (u < 0 || l < 0)
    return "IMPOSSIBLE";

可以在for 循环之前添加。并且可以在循环中添加更多检查。在现实世界中,它可能会使代码变慢或变快,这取决于许多因素(分支预测,更可能或不可能......)。它不会改变复杂性。

【讨论】:

  • 太棒了。同样在您的代码中只有一个 for 循环,这比我原来的解决方案要快。
  • @ZhaoGang stream 也会遍历所有元素,因此它与另一个 for 循环相同。我想知道速度得分是多少。
  • 确实如此。通常(至少在 Leetcode 中),O(2n) 和 O(n) 解决方案都应该通过所有测试用例。时间限制异常只发生在时间复杂度大于 O(n) 的情况下,例如 O(nlng) 或 O(n^2) @Oleg
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-20
相关资源
最近更新 更多