Tricoloring整数数组

时间:2017-06-06 12:59:36

标签: php arrays algorithm

我在PHP中被分配了一个任务 - 就像这样:

  

给出了由N个整数组成的零索引数组A.这个数组的三角形是一个由N个字符组成的字符串,这样每个字符都是' R' R' (意思是红色),' G' (绿色)或' B' (蓝色)。串的K th 字符(其中0≤K th 元素的颜色。

     

如果红色元素的总和等于绿色元素的总和以及蓝色元素的总和,则tricoloring是稳定的。 Tricoloring不一定使用所有三种颜色。假设未使用的颜色的元素总和为0.

     

例如,考虑数组A

A[0] = 3    A[1] = 7    A[2] = 2    A[3] = 5    A[4] = 4
     

字符串" RRGGB"是这个数组的示例tricoloring。它不稳定,因为A [0] + A [1] = 10,A [2] + A [3] = 7,A [4] = 4和10≠7≠4。另一方面,tricoloring " RGBBR"是稳定的,因为A [0] + A [4] = 7; A [1] = 7且A [2] + A [3] = 7。

     

写一个函数

function solution($A);
     

给定由N个整数组成的零索引数组A,返回该数组的任何稳定的tricoloring。该函数应该返回字符串"不可能"如果不存在稳定的tricoloring。

     

假设:

     
      
  • N是[0..18]范围内的整数;
  •   
  • 数组A的每个元素是[-100,000,000 ... 100,000,000]范围内的整数。
  •   
     

例如,给定数组A

A[0] = 3    A[1] = 7    A[2] = 2    A[3] = 5    A[4] = 4
     

该函数可以返回" RGBBR",如上所述。给定数组A

A[0] = 3    A[1] = 6    A[2] = 9
     

该功能应该返回"不可能"。

     

复杂度:

     

预期的最坏情况时间复杂度为O(N * 2N);
  预期的最坏情况空间复杂度为O(2N),超出输入存储(不计入输入参数所需的存储空间)   可以修改输入数组的元素。

我正在尝试通过以下代码执行此任务:

function solution($array) {        
    $sum = 0;
    $temp;
    $divison = 0;
    $length = count($array);
    $sum = array_sum($array);
    $divison = ($sum/3);
    $concatString = '';
    $ResultArray = $skips = array();

    for ($i = 0; $i < $length; $i++) {
        $j = $i;
        for ($j = 0; $j < $length; $j++) {
            if ($array[$i] == $divison) {
                $ResultArray[$i] = "R";
            }
            if (($array[$i]+$array[$j]) == $divison) {
                $ResultArray[$i] = "G";
                $ResultArray[$j] = "B";                 
            }                       
        }
    }

    print_r($ResultArray);
    ksort($ResultArray);
    print_r($ResultArray);
}

$Array = array(3, 7, 2 , 5 , 4);
solution($Array);

这会打印不正确的结果。我做错了什么?

4 个答案:

答案 0 :(得分:2)

除了一些明显的错误($j循环覆盖了for之后),你只关注价值恰好是总和的三分之一的情况,而有还可以通过将不同的值一起添加来达到此值的情况。

第一项检查是值的总和是3的倍数(就像你已经做过的那样)。

然后,您可以使用递归算法,在每个递归级别,您可以查看数组中的下一个值,并决定是否将红色指定给它(是或否)。

如果在某个时刻达到所需的总和(总数的1/3),则继续递归,但从第一个值开始,然后决定是否将颜色绿色分配给数组中的一个特定值(是还是不是)。当然,当红色已经分配给它时,你不能指定绿色,所以在这种情况下,没有真正的决定(它是否定的)。

如果那时你可以获得所需的总和,你就有了一个解决方案:所有未指定的值都是蓝色的。

以下是这样的实施:

function solution($arr) {
    $sum = array_sum($arr);
    if ($sum % 3) return "impossible";
    $division = $sum / 3;

    function recurse(&$arr, &$result, $division, $color, $sum, $i) {
        if ($sum === $division) {
            // We got the right sum for one color. 
            // If this was the second color, we have a solution
            if ($color === "G") return true;
            // If this was the first color (R), then now assign the second (G).
            // Don't assign Green before the first Red, as that would be just
            // an inversion of colors. Our solution will have B before the first
            // R, and R before the first G.
            $first = array_search("R", $result);
            return recurse($arr, $result, $division, "G", 0, $first+1);
        }
        if ($i >= count($arr)) return false; // failed to match the division
        // First, try without coloring this value:
        $success = recurse($arr, $result, $division, $color, $sum, $i+1);
        if ($success) return true;
        // Secondly, try coloring this value, if it was not yet colored (blue is default):
        if ($result[$i] === "B") {
            $result[$i] = $color;
            $success = recurse($arr, $result, $division, $color, $sum + $arr[$i], $i+1);
            if ($success) return true;
            $result[$i] = "B"; // Set back to default color
        }
        // No luck. Backtrack
        return false;
    }

    // Initialise the solution array with only blue values
    $result = array_fill(0, count($arr), "B"); // Fill with default color (i.e. "B");
    if ($division === 0) return $result; // no need to look further

    // Recurse to assign red to some values, and after that: green to some other values, but let the first value stay assigned to blue (as it could be any).
    $success = recurse($arr, $result, $division, "R", 0, 1);
    return $success ? implode($result, "") : "impossible";
}

// Sample run:
$arr = array(3, 7, 2, 5, 4);

$result = solution($arr);
echo $result . "\n";

查看它在repl.it;

上运行

N 时间复杂度的概念没有意义,因为 N 最多为18个。但是如果我们暂时忽略对 N的限制,时间复杂度取决于所有配置在每个索引处都有三种颜色中的任何一种。

有一个无关紧要的优化会使算法只查看将B分配给第一个值的配置,并将R分配给未分配给B的第一个值。

所以这会使它在 O(3 N 中运行。

答案 1 :(得分:0)

colors = ['R', 'G', 'B']

def isStableColor(A, colPlacements):
    color_r = 0
    color_g = 0
    color_b = 0
    for i in range(len(colPlacements)):
        if colPlacements[i] == 'R':
            color_r += A[i]
        if colPlacements[i] == 'G':
            color_g += A[i]
        if colPlacements[i] == 'B':
            color_b += A[i]

    if color_r == color_g and color_g == color_b and color_r == color_b:
        # found the solution
        return ''.join(colPlacements)
    else:
        return False


def solveColor(A, row, colPlacements, result):
    if row == len(A):
        is_stable = isStableColor(A, colPlacements)
        if is_stable != False:
            result.append(s)

    else:

        for col in range(len(A)):

            for color in colors:
                colPlacements.append(color)

                solveColor(A, row + 1, colPlacements, result)

                colPlacements.pop()  # backtracking

    return result

def solution(A):

    # lets take one element which can be either R G B ( 3 possibilities)

    colPlacements = []
    result = []

    solveColor(A, 0, colPlacements, result)

    return result


if __name__ == "__main__":

    s = solution( [3, 7, 2, 5, 4 ] )
    print s #there might be many possible solutions 

答案 2 :(得分:0)

我没有用php编写代码,但是如果有帮助的话,可以用JS解决方案。 工作demo here

let fillColor = (colored, arr, requiredSum, currVal, color) => {
    let added = false
    for(let idx =0; idx<colored.length; idx++) {
        if (!colored[idx]) { // iterate over only those idx which are not colored.
            let tempSum = currVal + arr[idx];

            if (tempSum === requiredSum) { // exit if colored;
                added = true;
                colored[idx] = color;
                break;
            } else if (tempSum < requiredSum) { // if coloring not completed;
                let newColored = [...colored]
                newColored[idx] = color;
                let retColored = fillColor(newColored, arr, requiredSum, tempSum, color)
                if (retColored) {
                    added = true;
                    colored = retColored
                    break;
                } 
            } 
        }
    };
    return added ? colored : false;
}


let solution = (arr) => {
    let colored = new Array(arr.length)
    // Number of colors, R, G, B
    let k = 3
    let arrSum = arr.reduce((a,b) => a+b, 0);

    // See if sum of array is divisible by k;
    if (arrSum%k === 0 && arr.length >= k) {
        let requiredSumOfSubset = arrSum / k;
        colored = fillColor(colored, arr, requiredSumOfSubset, 0, 'R')
        colored = fillColor(colored, arr, requiredSumOfSubset, 0, 'G')
        colored = fillColor(colored, arr, requiredSumOfSubset, 0, 'B')
        if (colored) {
            // Print colored string
            console.log(colored.join(''));
        } else {
            console.log("can't be colored equally");    
        }
    } else {
        console.log("impossible to tri-color");
    }
}

// Some test cases.
solution([5,3,7,2,4]);
solution([3,2,1]); // can't be colored even though sum is divisible by 3
solution([5,5,5]);
solution([4,5]); // impossible to color even though sum is divisible by 3
solution([4,5,7]); // impossible to color;
solution([5,2,5,1,4,1,3]);

答案 3 :(得分:0)

public String solution(int[] A) {
    String finalOP = "impossible";
    String[] colored = new String[A.length];
    int k = 3;
    List<Integer> numbers = Arrays.stream(A).boxed().collect(Collectors.toList());
    Integer arrSum = numbers.stream().reduce(0, ((a, b) -> a + b));
    if (arrSum % k == 0 && A.length >= k) {
        int requiredSumOfSubset = arrSum / k;
        colored = fillColor(colored, A, requiredSumOfSubset, 0, "R");
        colored = fillColor(colored, A, requiredSumOfSubset, 0, "G");
        colored = fillColor(colored, A, requiredSumOfSubset, 0, "B");
        if (colored.length > 0) {
            StringBuilder sb = new StringBuilder();
            for (String str : colored)
                sb.append(str);
            finalOP = sb.toString();
        }
    }
    return finalOP;
}

private String[] fillColor(String[] colored, int[] arr, int requiredSum, int currVal, String color) {
    boolean added = false;
    for (int idx = 0; idx < colored.length; idx++) {
        if (colored[idx] == null) {
            int tempSum = currVal + arr[idx];
            if (tempSum == requiredSum) {
                added = true;
                colored[idx] = color;
                break;
            } else if (tempSum < requiredSum) {
                String[] newColored = colored;
                newColored[idx] = color;
                String[] retColored = fillColor(newColored, arr, requiredSum, tempSum, color);
                if (retColored.length > 0) {
                    added = true;
                    colored = retColored;
                    break;
                }
            }
        }
    }

    String[] arrNew = new String[0];
    return added ? colored : arrNew;
}