[英]Sudoku algorithm in C#
我需要一个衬垫(或靠近它)来验证给定的9个元素的数组不包含重复的数字1,2,3,...,9。 重复零不计数(它们代表空单元格)。
到目前为止我得到的最好的是:
var a = new int[9] {1,2,3,4,5,6,7,8,9};
var itIsOk = a.Join(a, i => i, j => j, (x, y) => x)
.GroupBy(y => y).Where(g => g.Key > 0 && g.Count() > 1).Count() == 0;
如果你不想解决我的问题:),你至少可以告诉上述算法是否正常工作吗?
并且,是的,已经读过这个 。
这比LINQ解决方案快大约50-250倍(取决于复制的早期时间):
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;
}
幸运的是,我不久前自己建造了一个数独求解器:)整个事情大约是200行C#,它可以解决我在4秒或更短时间内找到的最棘手的难题。
由于使用.Count,性能可能不是很好,但它应该工作:
!a.Any(i => i != 0 && a.Where(j => j != 0 && i == j).Count > 1)
此外, j != 0
部分并不是真正需要的,但它应该有助于事情运行得更快。
[编辑:] kvb的回答给了我另一个想法:
!a.Where(i => i != 0).GroupBy(i => i).Any(gp => gp.Count() > 1)
在分组之前过滤0。 虽然基于IEnumerable的工作方式,但它可能无关紧要。
无论哪种方式,为了获得最佳性能,请使用新的IEnumerable扩展方法替换.Count > 1
,如下所示:
bool MoreThanOne(this IEnumerable<T> enumerable, Predictate<T> pred)
{
bool flag = false;
foreach (T item in enumerable)
{
if (pred(item))
{
if (flag)
return true;
flag = true;
}
}
return false;
}
它可能无关紧要,因为数组限制为9个项目,但如果你调用它很多,它可能会加起来。
!a.GroupBy(i => i).Any(gp => gp.Key != 0 && gp.Count() > 1)
这是一个老问题,但我最近指出使用Oracle的自定义SQL进行树状结构的1行解决方案。 我认为把它转换成Linq会很好。
您可以在我的博客上阅读更多关于如何在Linq的1行中解决数独的内容
这是代码:
public static string SolveStrings(string Board)
{
string[] leafNodesOfMoves = new string[] { Board };
while ((leafNodesOfMoves.Length > 0) && (leafNodesOfMoves[0].IndexOf(' ') != -1))
{
leafNodesOfMoves = (
from partialSolution in leafNodesOfMoves
let index = partialSolution.IndexOf(' ')
let column = index % 9
let groupOf3 = index - (index % 27) + column - (index % 3)
from searchLetter in "123456789"
let InvalidPositions =
from spaceToCheck in Enumerable.Range(0, 9)
let IsInRow = partialSolution[index - column + spaceToCheck] == searchLetter
let IsInColumn = partialSolution[column + (spaceToCheck * 9)] == searchLetter
let IsInGroupBoxOf3x3 = partialSolution[groupOf3 + (spaceToCheck % 3) +
(int)Math.Floor(spaceToCheck / 3f) * 9] == searchLetter
where IsInRow || IsInColumn || IsInGroupBoxOf3x3
select spaceToCheck
where InvalidPositions.Count() == 0
select partialSolution.Substring(0, index) + searchLetter + partialSolution.Substring(index + 1)
).ToArray();
}
return (leafNodesOfMoves.Length == 0)
? "No solution"
: leafNodesOfMoves[0];
}
为什么你需要一个复杂的Linq代码行,而不是在扩展方法中包含一个有效的测试实现并调用它?
var a = new int[9] {1,2,3,4,5,6,7,8,9};
var itIsOk = a.HasNoNonZeroRepeats();
NoNonZeroRepeats的一个实现可能是使用short的9个最低位来指示数组中存在值,从而在没有动态内存使用的情况下进行O(长度(a))测试。 Linq很可爱,但除非你出于审美原因只使用它(你没有特别说你只用Linq作为练习来编写数独求解器),这似乎只是增加了复杂性。
为简洁起见,如果不是性能,var itIsOk = a.Sum()== a.Distinct()。Sum();
怎么样:
var itIsOk = a.Where(x => x > 0).Distinct().Count() == a.Where(x => x > 0).Count();
推理:首先创建一个没有0的枚举。 在剩余的数字中,如果其不同的列表与实际列表的长度相同,则没有重复。
或:如果唯一编号列表小于实际列表,则必须具有重复编号。
这是单行版本。 a.Where(x => x> 0)列表可以被排除在外。
var nonZeroList = a.Where(x => x > 0).ToList();
var itIsOk = nonZeroList.Distinct().Count() == nonZeroList.Count();
我通常对涉及捕获变量的解决方案不满意,但我有一种写这个的冲动:
bool hasRepeating = false;
int previous = 0;
int firstDuplicateValue = a
.Where(i => i != 0)
.OrderBy(i => i)
.FirstOrDefault(i =>
{
hasRepeating = (i == previous);
previous = i;
return hasRepeating;
});
if (hasRepeating)
{
Console.WriteLine(firstDuplicateValue);
}
以下内容简单快捷。
if a.Select(i => Math.Pow(2, i - 1)).ToArray().Sum()==511 ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.