给定一个二维数组 arr 和一个目标 target,从数组中找出和 target 关联的所有元素。
示例1:
给定一个列表如下,[1,2] 表示 1 和 2 具有关联性
输入:arr=[[1,2],[3,4],[9,4],[4,5],[4,6],[4,7],[7,11],[6,12],[11,15]],target=4
输出:3,4,5,6,7,9,11,12,15
解释:这些数字都具有关联性
对于关联性问题,可以采用无向图的思路进行解决
c# 代码如下
internal class Program
{
static void Main(string[] args)
{
InitAdjacencyList(InitAssociations(3));// 改变参数测试其他用例
long target = 0;
while (true)
{
Console.WriteLine("请输入查找的节点:");
string value = Console.ReadLine();
long.TryParse(value, out target);
HashSet<long> set = new HashSet<long>();
HashSet<long> foundList = new HashSet<long>();
Dictionary<long, ListNode<long>> dict = AdjacencyList;
if (dict != null && dict.Keys.Count > 0)
{
FindAssoData(ref set, dict, target, ref foundList);
}
set.Remove(target);
set = set.OrderBy(x => x).ToHashSet();
Console.WriteLine($"和 {target} 相连的节点为:" + string.Join(",", set));
}
}
/// <summary>
/// 找到和 target 具有关联的所有结果,广度优先,时间复杂度 nlog(n)
/// </summary>
/// <param name="set"></param>
/// <param name="dict"></param>
/// <param name="target"></param>
/// <param name="foundList"></param>
private static void FindAssoData(ref HashSet<long> set, Dictionary<long, ListNode<long>> dict, long target, ref HashSet<long> foundList)
{
if (foundList.Contains(target)) return;
foreach (long key in dict.Keys)
{
if (key.Equals(target))
{
ListNode<long> head = dict[target].Head;
ListNode<long> node = head.Next;
while (node != null)
{
set.Add(node.Data);
node = node.Next;
}
}
else
{
// 遍历链表,找到符合 target 的节点
ListNode<long> head = dict[key].Head;
bool found = false;
ListNode<long> node = head.Next;
while (node != null)
{
if (node.Data == target)
{
found = true;
break;
}
else
{
node = node.Next;
}
}
if (found)
{
set.Add(key);
node = head.Next;
while (node != null)
{
set.Add(node.Data);
node = node.Next;
}
}
}
}
foundList.Add(target);
// bfs
foreach (long item in set.ToArray())
{
FindAssoData(ref set, dict, item, ref foundList);
}
}
public static Dictionary<long, ListNode<long>> AdjacencyList { get; set; }
public static List<Association> InitAssociations(int idx = 0)
{
List<Association> Associations = new List<Association>();
if (idx == 0)
{
/** dict ***
* 1->2
* 3->4
* 9->4
* 4->5->6->7
* 7->11
* 6->12
* 11->15
*
* target=4 => 3,4,5,6,7,9,11,12,15
*/
Associations.Add(new Association(1, 2));
Associations.Add(new Association(3, 4));
Associations.Add(new Association(9, 4));
Associations.Add(new Association(4, 5));
Associations.Add(new Association(4, 6));
Associations.Add(new Association(4, 7));
Associations.Add(new Association(7, 11));
Associations.Add(new Association(6, 12));
Associations.Add(new Association(11, 15));
}
else if (idx == 1)
{
/** dict ***
* 1->2
* 3->4
* 4->3
* 5->6->7
* 7->11
* 6->12
* 15->11->12
*
* target=12 => 5,6,7,11,15
*/
Associations.Add(new Association(1, 2));
Associations.Add(new Association(3, 4));
Associations.Add(new Association(4, 3));
Associations.Add(new Association(5, 6));
Associations.Add(new Association(5, 7));
Associations.Add(new Association(7, 11));
Associations.Add(new Association(6, 12));
Associations.Add(new Association(15, 11));
Associations.Add(new Association(15, 12));
}
else if (idx == 2)
{
/** dict ***
* 1->2
* 3->4
* 5->6
* 7->8
*
* target=12 => 5,6,7,11,15
*/
Associations.Add(new Association(1, 2));
Associations.Add(new Association(3, 4));
Associations.Add(new Association(5, 6));
Associations.Add(new Association(7, 8));
}
else if (idx == 3)
{
/** dict ***
* 1->2->3->4->5->6->7->8->9-10
* 3->4
* 5->6
* 7->8
* 11->12
* 12->15
* 15->1
* 16->17->18
* 19->20->16
* target=12 => 5,6,7,11,15
*/
Associations.Add(new Association(1, 2));
Associations.Add(new Association(1, 3));
Associations.Add(new Association(1, 4));
Associations.Add(new Association(1, 5));
Associations.Add(new Association(1, 6));
Associations.Add(new Association(1, 7));
Associations.Add(new Association(1, 8));
Associations.Add(new Association(1, 9));
Associations.Add(new Association(1, 10));
Associations.Add(new Association(3, 4));
Associations.Add(new Association(5, 6));
Associations.Add(new Association(7, 8));
Associations.Add(new Association(11, 12));
Associations.Add(new Association(12, 15));
Associations.Add(new Association(15, 1));
Associations.Add(new Association(16, 17));
Associations.Add(new Association(16, 18));
Associations.Add(new Association(19, 20));
Associations.Add(new Association(19, 16));
}
return Associations;
}
public static void InitAdjacencyList(List<Association> associations)
{
AdjacencyList = new Dictionary<long, ListNode<long>>();
// 构造邻接表
// 邻接表适合存储稀疏图(顶点较多、边较少)
if (associations != null && associations.Count > 0)
{
foreach (Association asso in associations)
{
long dataId = asso.MainDataID;
if (AdjacencyList.ContainsKey(dataId))
{
ListNode<long> node = AdjacencyList[dataId];
while (true)
{
if (node.Next == null)
{
node.Next = new ListNode<long>(asso.SubDataID);
break;
}
else
{
node = node.Next;
}
}
}
else
{
ListNode<long> node = new ListNode<long>(asso.SubDataID);
ListNode<long> head = new ListNode<long>(-1);
head.Next = node;
node.Head = head;
AdjacencyList.Add(dataId, node);
}
}
// 打印邻接矩阵
foreach (long key in AdjacencyList.Keys)
{
StringBuilder builder = new StringBuilder();
builder.Append($"{key}->");
ListNode<long> head = AdjacencyList[key].Head;
ListNode<long> node = head.Next;
while (node != null)
{
builder.Append($"{node.Data}->");
node = node.Next;
if (node == null) builder.Remove(builder.Length - 2, 2);
}
Console.WriteLine(builder);
}
}
//Console.WriteLine();
}
}
public class ListNode<T>
{
public T Data { get; set; }
public ListNode<T> Next { get; set; }
public ListNode<T> Head { get; set; }
public ListNode(T item)
{
Data = item;
}
}
public class Association
{
public long MainDataID { get; set; }
public long SubDataID { get; set; }
public Association(long d1, long d2)
{
MainDataID = d1;
SubDataID = d2;
}
}