假设您需要计算矩阵上的孤岛数量
{1, 1, 0, 0, 0},
{0, 1, 0, 0, 1},
{1, 0, 0, 1, 1},
{0, 0, 0, 0, 0},
{1, 0, 1, 0, 1}
当输入矩阵大小适合内存时,我们可以简单地使用DFS或BFS。
但是,如果输入矩阵很大而无法放入内存,该怎么办?
我可以将输入矩阵分块/拆分为不同的小文件,然后分别读取它们。
但是如何合并它们呢?
我陷入了如何合并它们的困境。我的想法是,合并它们时,我们必须阅读一些重叠的部分。但是,这样做的具体方法是什么?
当我在白板上绘制以下示例并逐行处理它时。合并左,然后合并顶部,这似乎行不通。
来自Matt的解决方案。
int topidx = col * 2;
int botidx = topidx + 1;
使用联合查找,基本算法(无需担心内存)是:
1
1
s 的集合。顺序是什么都没关系,因此阅读顺序通常很好。简单,一点点地注意,就可以使用对矩阵的顺序访问和仅2行的内存来做到这一点:
1
,然后合并相邻列中的集合。对于每个其他行:
1
,然后将相邻列中的集合合并;当然,关键是只要您在不同行中的链接集始终将链接指向下方。这不会损害算法的复杂性,而且,如果您使用自己的联合查找,则很容易实现。如果您使用的是库数据结构,则可以仅对每一行使用它,并自己跟踪不同行中的根集之间的链接。
因为这实际上是我最喜欢的算法之一,所以这里是Java的实现。这不是最易读的实现,因为它涉及一些低级技巧,但是效率极高且简短-
我会在性能非常重要的情况下写这种东西:
import java.util.Arrays;
public class Islands
{
private static final String[] matrix=new String[] {
" ############# ### ",
" # ##### ## ",
" # ## ## # # ",
" ### ## # # ",
" # ######### ## ## ",
" ## ## ",
" ########## ",
};
// find with path compression.
// If sets[s] < 0 then it is a link to ~sets[s]. Otherwise it is size of set
static int find(int[] sets, int s)
{
int parent = ~sets[s];
if (parent>=0)
{
int root = find(sets, parent);
if (root != parent)
{
sets[s] = ~root;
}
return root;
}
return s;
}
// union-by-size
// If sets[s] < 0 then it is a link to ~sets[s]. Otherwise it is size of set
static boolean union(int[] sets, int x, int y)
{
x = find(sets,x);
y = find(sets,y);
if (x!=y)
{
if ((sets[x] < sets[y]))
{
sets[y] += sets[x];
sets[x] = ~y;
}
else
{
sets[x] += sets[y];
sets[y] = ~x;
}
return true;
}
return false;
}
// Count islands in matrix
public static void main(String[] args)
{
// two rows of union-find sets.
// top row is at even indexes, bottom row is at odd indexes. This arrangemnt is chosen just
// to make resizing this array easier.
// For each value x:
// x==0 => no set. x>0 => root set of size x. x<0 => link to ~x
int cols=4;
int[] setrows= new int[cols*2];
int islandCount = 0;
for (String s : matrix)
{
System.out.println(s);
//Make sure our rows are big enough
if (s.length() > cols)
{
cols=s.length();
if (setrows.length < cols*2)
{
int newlen = Math.max(cols,setrows.length)*2;
setrows = Arrays.copyOf(setrows, newlen);
}
}
//Create sets for land in bottom row, merging left
for (int col=0; col<s.length(); ++col)
{
if (!Character.isWhitespace(s.charAt(col)))
{
int idx = col*2+1;
setrows[idx]=1; //set of size 1
if (idx>=2 && setrows[idx-2]!=0)
{
union(setrows, idx, idx-2);
}
}
}
//merge up
for (int col=0; col<cols; ++col)
{
int topidx = col*2;
int botidx = topidx+1;
if (setrows[topidx]!=0 && setrows[botidx]!=0)
{
int toproot=find(setrows,topidx);
if ((toproot&1)!=0)
{
//top set is already linked down
union(setrows, toproot, botidx);
}
else
{
//link top root down. It does not matter that we aren't counting its size, since
//we will shortly throw it aaway
setrows[toproot] = ~botidx;
}
}
}
//count root sets, discard top row, and move bottom row up while fixing links
for (int col=0; col<cols; ++col)
{
int topidx = col * 2;
int botidx = topidx + 1;
if (setrows[topidx]>0)
{
++islandCount;
}
int v = setrows[botidx];
setrows[topidx] = (v>=0 ? v : v|1); //fix up link if necessary
setrows[botidx] = 0;
}
}
//count remaining root sets in top row
for (int col=0; col<cols; ++col)
{
if (setrows[col*2]>0)
{
++islandCount;
}
}
System.out.println("\nThere are "+islandCount+" islands there");
}
}
我这个星期天要参加考试,我只想确认我正在做的事情是否正确(你知道考试让我持怀疑态度) 这就是算法的工作原理: 这就是问题所在: 回想一下为不相交集开发的算法,这些不相交集来自一组n个元素。查找使用路径压缩,联合使用排名。此外,相同等级的两棵树的联合选择与第二个参数关联的根作为新根。从一个集合S={1,2,…,10}和10个不相交子集开始,每个子集都包含一个元素。a.执行后绘制最后一组树: Unio
处理以下问题(https://leetcode.com/problems/friend-circles/): 一个班有N个学生。他们有些是朋友,有些不是。他们的友谊本质上是可传递的。比如A是B的直接好友,B是C的直接好友,那么A就是C的间接好友,而我们定义的朋友圈就是一群直接或者间接好友的同学。 给定一个N*N矩阵M,表示班级学生之间的朋友关系。如果M[i][j]=1,则第i和第j个学生是彼此的直
我有一个项目,我必须实现一个带有路径压缩算法的加权快速并集。在看到其他一些源代码后,我最终得到了这个: 分配给我的任务是正确完成以下方法: int find(int v) void unite(int v,int u) setCount(int v) 嗯,算法似乎很慢,我找不到合适的解决方案。
我正在努力对与CRC-16校验和相关的一段数据进行反向工程。我知道用来计算原始校验和的多项式是,但没有别的,我不知道初始值(如果有),最终异或值(如果有),如果输入或结果被反映... 似乎有一个已知的CRC-16生成器使用thing polynom,CRC-16-CCITT,但尽管我尝试了所有的方法,我还是不能理解原始校验和是如何计算的。
ASL 由于查找算法的主要运算是关键字的比较,所以通常把查找过程中对关键字的平均比较次数(平均查找长度)作为衡量一个查找算法效率的标准。ASL= ∑(n,i=1) Pi*Ci,其中n为元素个数,Pi是查找第i个元素的概率,一般为Pi=1/n,Ci是找到第i个元素所需比较的次数。 顺序查找 原理是让关键字与队列中的数从最后一个开始逐个比较,直到找出与给定关键字相同的数为止,它的缺点是效率低下。时间复
假设我有一个无向多图,即一个(G,E)对,其中G是一个有限的结点集,E是一个有限的边集。我正在寻找一个算法,将分配一个单一的字符串值到每个节点在以下的约束。 1. 每个节点都被赋予一组约束(可能是空的),这些约束限制了允许的值。我希望至少支持以下类型的值约束: null 有两种类型的边缘: 不同, 相同, 这意味着应该为相关节点分配不同/相同的值(意味着不相等/相等的字符串)。 null 这意味着