数独有效性检查算法 - 这段代码是如何工作的?

发布于 2024-10-19 06:22:38 字数 608 浏览 7 评论 0原文

我正在阅读此处发布的一个问题: C# 中的数独算法

发布的解决方案之一是这个一段代码。

public static bool IsValid(int[] values) {
        int flag = 0;
        foreach (int value in values) {
                if (value != 0) {
                        int bit = 1 << value;
                        if ((flag & bit) != 0) return false;
                        flag |= bit;
                }
        }
        return true;
}

这个想法是它将检测值数组中的重复项;但我对自己的无知感到不知所措。有人可以向我解释一下吗?

编辑:谢谢大家。这么多精彩的答案,我不知道如何选择一个。现在它完全有道理了。

I was reading a question posted here: Sudoku algorithm in C#

And one of the solutions posted was this piece of code.

public static bool IsValid(int[] values) {
        int flag = 0;
        foreach (int value in values) {
                if (value != 0) {
                        int bit = 1 << value;
                        if ((flag & bit) != 0) return false;
                        flag |= bit;
                }
        }
        return true;
}

The idea is that it will detect duplicates in the array of values; but I'm overwhelmed by how much I don't know. Can someone explain this to me?

EDIT: Thanks everyone. So many great answers, I don't know how to select one. It now makes perfect sense.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

箹锭⒈辈孓 2024-10-26 06:22:38

真是个好主意。

基本上,它使用 int 标志(最初设置为零)作为“位数组”;对于每个值,它检查标志中的相应位是否已设置,如果没有,则设置它。

相反,如果该位位置已设置,则它知道相应的值已被看到,因此该数独块无效。

更详细:

public static bool IsValid(int[] values)
{
    // bit field (set to zero => no values processed yet)
    int flag = 0;
    foreach (int value in values)
    {
        // value == 0 => reserved for still not filled cells, not to be processed
        if (value != 0)
        {
            // prepares the bit mask left-shifting 1 of value positions
            int bit = 1 << value; 
            // checks if the bit is already set, and if so the Sudoku is invalid
            if ((flag & bit) != 0)
                return false;
            // otherwise sets the bit ("value seen")
            flag |= bit;
        }
    }
    // if we didn't exit before, there are no problems with the given values
    return true;
}

Really a nice idea.

Basically, it uses an int flag (initially set to zero) as a "bit array"; for each value, it checks if the corresponding bit in the flag is set, and if it's not, it sets it.

If, instead, that bit position is already set, it knows that the corresponding value has already been seen, so the piece of Sudoku is invalid.

More in detail:

public static bool IsValid(int[] values)
{
    // bit field (set to zero => no values processed yet)
    int flag = 0;
    foreach (int value in values)
    {
        // value == 0 => reserved for still not filled cells, not to be processed
        if (value != 0)
        {
            // prepares the bit mask left-shifting 1 of value positions
            int bit = 1 << value; 
            // checks if the bit is already set, and if so the Sudoku is invalid
            if ((flag & bit) != 0)
                return false;
            // otherwise sets the bit ("value seen")
            flag |= bit;
        }
    }
    // if we didn't exit before, there are no problems with the given values
    return true;
}
Spring初心 2024-10-26 06:22:38

让我们来解决它。
values = 1,2,3,2,5

迭代 1:

bit = 1 << 1 位 = 10

if(00 & 10 != 00) false

标志 |= 位 flag = 10

迭代 2:

bit = 1 << 2 位 = 100

if(010 & 100 != 000) false

标志 |= 位 flag = 110

迭代 3:

bit = 1 << 3 位 = 1000

if(0110 & 1000 != 0000) false

标志 |= 位 flag = 1110

迭代 4:

bit = 1 << 2 bit = 100

if(1110 & 0100 != 0000) TRUE 计算结果为 true,这意味着我们找到了一个 double ,并返回 false

Lets work through it.
values = 1,2,3,2,5

Iteration 1:

bit = 1 << 1 bit = 10

if(00 & 10 != 00) false

flag |= bit flag = 10

Iteration 2:

bit = 1 << 2 bit = 100

if(010 & 100 != 000) false

flag |= bit flag = 110

Iteration 3:

bit = 1 << 3 bit = 1000

if(0110 & 1000 != 0000) false

flag |= bit flag = 1110

Iteration 4:

bit = 1 << 2 bit = 100

if(1110 & 0100 != 0000) TRUE This evaluates to true, meaning we found a double, and return false

独夜无伴 2024-10-26 06:22:38

这个想法是设置数字的第 n 位,其中 n 是单元格值。由于数独值的范围为 1-9,因此所有位都在 0-512 的范围内。对于每个值,检查第 n 位是否已设置,如果是,则我们发现了重复项。如果没有,请设置支票号码的第 n 位(在本例中为标志),以累积已使用的号码。这是一种比数组更快的数据存储方式。

The idea is to set the nth bit of a number, where n is the cell value. Since sudoku values range from 1-9, all the bits fit within a range of 0-512. With each value, check if the nth bit is already set, and if so, we've found a duplicate. If not, set the nth bit on our check number, in this case flag, to accumulate numbers that have already been used. It's a much faster way to store data than an array.

故事↓在人 2024-10-26 06:22:38

有趣的。它通过在标志整数中设置该位来存储已经找到的数字。示例:

  • 它找到了 4 个
  • 移位,然后将数字 1 乘以 4 位,结果是位数组 00010000b
  • 或者将其放入 flag-int(之前为 0),结果是 flag-int 为 00010000b
  • 它找到了 2 个
  • 移位,然后将数字 1 通过2 位导致位数组 00000100b
  • 或进入 flag-int(之前为 00010000b)导致 flag-int 为 00010100b

它还测试每个数字是否已在 flag-int 中设置该位。

Interesting. It stores the numbers it already found by setting that bit in the flag-integer. Example:

  • It found a 4
  • Shift then number 1 by 4 bits resulting in the bit-array 00010000b
  • Or it into the flag-int (which was previously 0) results in the flag-int being 00010000b
  • It found a 2
  • Shift then number 1 by 2 bits resulting in the bit-array 00000100b
  • Or it into the flag-int (which was previously 00010000b) results in the flag-int being 00010100b

It also tests for each number if that bit is already set in the flag-int.

初熏 2024-10-26 06:22:38

它检查数组中的值是否唯一。为此,它创建一个整数 - 标志 - 并根据值数组中的值设置标志中的位。它检查某个特定位是否已设置;如果是,则存在重复并且失败。否则,它会设置该位。

这是一个细分:

public static bool IsValid(int[] values) {
        int flag = 0; // <-- Initialize your flags; all of them are set to 0000
        foreach (int value in values) { // <-- Loop through the values
                if (value != 0) { // <-- Ignore values of 0
                        int bit = 1 << value; // <-- Left-shift 1 by the current value
// Say for example, the current value is 4, this will shift the bit in the value of 1
// 4 places to the left. So if the 1 looks like 000001 internally, after shifting 4 to the 
// left, it will look like 010000; this is how we choose a specific bit to set/inspect
                        if ((flag & bit) != 0) return false; // <-- Compare the bit at the
// position specified by bit with the corresponding position in flag. If both are 1 then
// & will return a value greater than 0; if either is not 1, then & will return 0. E.g.
// if flag = 01000 and bit = 01000, then the result will be 01000. If flag = 01000 and 
//bit = 00010 then the result will be 0; this is how we check to see if the bit 
// is already set. If it is, then we've already seen this value, so return false, i.e. not
// a valid solution
                        flag |= bit; // <-- We haven't seen this value before, so set the 
// corresponding bit in the flag to say we've seen it now. e.g. if flag = 1000 
// and bit = 0100, after this operation, flag = 1100
                }
        }
        return true; // <-- If we get this far, all values were unique, so it's a valid
// answer.
}

It checks to see if values in the array are unique. To do this, it creates an integer - flag - and it sets bits in the flag according to values in the array of values. It checks to see if a particular bit is already set; if it is, then there is a duplicate and it fails. Otherwise, it sets the bit.

Here's a breakdown:

public static bool IsValid(int[] values) {
        int flag = 0; // <-- Initialize your flags; all of them are set to 0000
        foreach (int value in values) { // <-- Loop through the values
                if (value != 0) { // <-- Ignore values of 0
                        int bit = 1 << value; // <-- Left-shift 1 by the current value
// Say for example, the current value is 4, this will shift the bit in the value of 1
// 4 places to the left. So if the 1 looks like 000001 internally, after shifting 4 to the 
// left, it will look like 010000; this is how we choose a specific bit to set/inspect
                        if ((flag & bit) != 0) return false; // <-- Compare the bit at the
// position specified by bit with the corresponding position in flag. If both are 1 then
// & will return a value greater than 0; if either is not 1, then & will return 0. E.g.
// if flag = 01000 and bit = 01000, then the result will be 01000. If flag = 01000 and 
//bit = 00010 then the result will be 0; this is how we check to see if the bit 
// is already set. If it is, then we've already seen this value, so return false, i.e. not
// a valid solution
                        flag |= bit; // <-- We haven't seen this value before, so set the 
// corresponding bit in the flag to say we've seen it now. e.g. if flag = 1000 
// and bit = 0100, after this operation, flag = 1100
                }
        }
        return true; // <-- If we get this far, all values were unique, so it's a valid
// answer.
}
伏妖词 2024-10-26 06:22:38
 int bit = 1 << value; //left bit shift - selects the bit that corresponds to value
 if ((flag & bit) != 0) return false; //bitwise AND - checks the flag to see whether bit is already set
 flag |= bit; // bitwise OR - sets the bit in the flag
 int bit = 1 << value; //left bit shift - selects the bit that corresponds to value
 if ((flag & bit) != 0) return false; //bitwise AND - checks the flag to see whether bit is already set
 flag |= bit; // bitwise OR - sets the bit in the flag
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文