C# 查找包含查询数组所有元素的输入数组的最小窗口
问题:给定一个由大小为n的整数组成的输入数组和一个由大小为k的整数组成的查询数组,找到输入数组中包含查询数组所有元素且顺序相同的最小窗口 我试过下面的方法C# 查找包含查询数组所有元素的输入数组的最小窗口,c#,algorithm,data-structures,collections,C#,Algorithm,Data Structures,Collections,问题:给定一个由大小为n的整数组成的输入数组和一个由大小为k的整数组成的查询数组,找到输入数组中包含查询数组所有元素且顺序相同的最小窗口 我试过下面的方法 int[] inputArray = new int[] { 2, 5, 2, 8, 0, 1, 4, 7 }; int[] queryArray = new int[] { 2, 1, 7 }; 将查找inputArray中所有查询数组元素的位置 public static void SmallestWin
int[] inputArray = new int[] { 2, 5, 2, 8, 0, 1, 4, 7 };
int[] queryArray = new int[] { 2, 1, 7 };
将查找inputArray中所有查询数组元素的位置
public static void SmallestWindow(int[] inputArray, int[] queryArray)
{
Dictionary<int, HashSet<int>> dict = new Dictionary<int, HashSet<int>>();
int index = 0;
foreach (int i in queryArray)
{
HashSet<int> hash = new HashSet<int>();
foreach (int j in inputArray)
{
index++;
if (i == j)
hash.Add(index);
}
dict.Add(i, hash);
index = 0;
}
// Need to perform action in above dictionary.??
}
publicstaticvoidsmallestwindow(int[]inputArray,int[]queryArray)
{
Dictionary dict=新字典();
int指数=0;
foreach(queryArray中的int i)
{
HashSet hash=新HashSet();
foreach(输入阵列中的int j)
{
索引++;
如果(i==j)
hash.Add(索引);
}
dict.Add(i,散列);
指数=0;
}
//需要执行上述字典中的操作。??
}
我找到了下面的字典
我无法理解如何比较字典的两个连续值。请帮助。我看不出使用
HashSet
和Dictionary
在这方面有什么帮助。如果我面对这个问题,我会采取完全不同的做法
一种方法(不是最有效的方法)如下所示。此代码假定queryArray
至少包含两项
int FindInArray(int[] a, int start, int value)
{
for (int i = start; i < a.Length; ++i)
{
if (a[i] == value)
return i;
}
return -1;
}
struct Pair
{
int first;
int last;
}
List<Pair> foundPairs = new List<Pair>();
int startPos = 0;
bool found = true;
while (found)
{
found = false;
// find next occurrence of queryArray[0] in inputArray
startPos = FindInArray(inputArray, startPos, queryArray[0]);
if (startPos == -1)
{
// no more occurrences of the first item
break;
}
Pair p = new Pair();
p.first = startPos;
++startPos;
int nextPos = startPos;
// now find occurrences of remaining items
for (int i = 1; i < queryArray.Length; ++i)
{
nextPos = FindInArray(inputArray, nextPos, queryArray[i]);
if (nextPos == -1)
{
break; // didn't find it
}
else
{
p.last = nextPos++;
found = (i == queryArray.Length-1);
}
}
if (found)
{
foundPairs.Add(p);
}
}
// At this point, the foundPairs list contains the (start, end) of all
// sublists that contain the items in order.
// You can then iterate through that list, subtract (last-first), and take
// the item that has the smallest value. That will be the shortest sublist
// that matches the criteria.
int FindInArray(int[]a,int start,int value)
{
对于(int i=开始;i
通过一些工作,可以提高效率。例如,如果“queryArray”包含
[1,2,3]
和inputArray
包含[1,7,4,9,1,3,6,4,1,8,2,3]
,则上述代码将找到三个匹配项(从位置0,4和8开始)。稍微聪明一点的代码可以确定,当在位置4处发现1
时,由于在此之前未发现2
,从第一个位置开始的任何序列都会比从位置4开始的序列长,因此会短路第一个序列并从新位置重新开始。不过,这使代码有点复杂。算法:对于查询数组中的每个元素,存储在映射M(V)中→ (I,P)),V是元素,I是输入数组的索引,P是查询数组中的位置。(输入数组中某些P的索引最大,因此查询[0..P]是输入[I..curr]的子序列) 遍历数组。
如果该值是查询数组中的第一项:将当前索引存储为I。
否则:存储查询数组中上一个元素的索引值,例如
M[currVal].I=M[query[M[currVal].P-1].I
如果该值是最后一项:检查[I..curr]是否为新的最佳值 复杂性
其复杂性为O(N),其中N是输入数组的大小 N.B.
这段代码要求查询数组中没有重复的元素。为此,我们可以使用地图M(V→ ((I,P))的列表。这是O(NhC(Q)),其中hC(Q)是查询数组的模式计数。
使用M(V)更好→ listOf((linkedList(I),P)))。当查询数组中连续出现重复元素时,我们使用链表。然后更新这些值成为O(1)。然后,复杂度为O(NhC(D(Q)),其中D(Q)是具有合并的连续项的Q 实施
示例java实现可用。这不适用于查询数组中的重复元素,也不适用于错误检查等。您希望字典中的值不是哈希集,而是(排序的)树或数组;字典包含从输入数组中找到的值到该值出现的(排序)索引列表的映射 然后你做下面的事情
- 查找查询中的第一个条目。选择它出现的最低索引
- 查找第二个条目;选择大于第一个索引的最低条目
- 查第三个;选择大于第二个的最小值。(等等)
- 当您到达查询中的最后一个条目时,(1+最后一个索引-第一个索引)是最小匹配的大小
- 现在选择第一个查询的第二个索引,重复,等等
2 --> position {0,2} // note: I change them to 0-based array
1 --> position {5,6} // I suppose it's {5,6} to make it more complex, in your code it's only {5}
7 --> position {7}
struct Pair
{
public int Number; // the number in queryArray
public int[] Indexes; // the positions of the number
}
static List<int[]> results = new List<int[]>(); //store all possible paths
static Stack<int> currResult = new Stack<int>(); // the container of current path
static int[] inputArray, queryArray;
static Pair[] pairs;
inputArray = new int[] { 2, 7, 1, 5, 2, 8, 0, 1, 4, 7 }; //my test case
queryArray = new int[] { 2, 1, 7 };
pairs = (from n in queryArray
select new Pair { Number = n, Indexes = inputArray.FindAllIndexes(i => i == n) }).ToArray();
Go(0);
public static int[] FindAllIndexes<T>(this IEnumerable<T> source, Func<T,bool> predicate)
{
//do necessary check here, then
Queue<int> indexes = new Queue<int>();
for (int i = 0;i<source.Count();i++)
if (predicate(source.ElementAt(i))) indexes.Enqueue(i);
return indexes.ToArray();
}
static void Go(int depth)
{
if (depth == pairs.Length)
{
results.Add(currResult.Reverse().ToArray());
}
else
{
var indexes = pairs[depth].Indexes;
for (int i = 0; i < indexes.Length; i++)
{
if (depth == 0 || indexes[i] > currResult.Last())
{
currResult.Push(indexes[i]);
Go(depth + 1);
currResult.Pop();
}
}
}
}
public static int[] SmallestWindow(int[] inputArray, int[] queryArray)
{
var indexed = queryArray
.SelectMany(x => inputArray
.Select((y, i) => new
{
Value = y,
Index = i
})
.Where(y => y.Value == x))
.OrderBy(x => x.Index)
.ToList();
var segments = indexed
.Select(x =>
{
var unique = new HashSet<int>();
return new
{
Item = x,
Followers = indexed
.Where(y => y.Index >= x.Index)
.TakeWhile(y => unique.Count != queryArray.Length)
.Select(y =>
{
unique.Add(y.Value);
return y;
})
.ToList(),
IsComplete = unique.Count == queryArray.Length
};
})
.Where(x => x.IsComplete);
var queryIndexed = segments
.Select(x => x.Followers.Select(y => new
{
QIndex = Array.IndexOf(queryArray, y.Value),
y.Index,
y.Value
}).ToArray());
var queryOrdered = queryIndexed
.Where(item =>
{
var qindex = item.Select(x => x.QIndex).ToList();
bool changed;
do
{
changed = false;
for (int i = 1; i < qindex.Count; i++)
{
if (qindex[i] <= qindex[i - 1])
{
qindex.RemoveAt(i);
changed = true;
}
}
} while (changed);
return qindex.Count == queryArray.Length;
});
var result = queryOrdered
.Select(x => new[]
{
x.First().Index,
x.Last().Index
})
.OrderBy(x => x[1] - x[0]);
var best = result.FirstOrDefault();
return best;
}
public void Test()
{
var inputArray = new[] { 2, 1, 5, 6, 8, 1, 8, 6, 2, 9, 2, 9, 1, 2 };
var queryArray = new[] { 6, 1, 2 };
var result = SmallestWindow(inputArray, queryArray);
if (result == null)
{
Console.WriteLine("no matching window");
}
else
{
Console.WriteLine("Smallest window is indexes " + result[0] + " to " + result[1]);
}
}
Smallest window is indexes 3 to 8
public class Pair
{
public int Number;
public List<int> Position;
}
public static Pair[] GetIndex(int[] inputArray, int[] query)
{
Pair[] pairList = new Pair[query.Length];
int pairIndex = 0;
foreach (int i in query)
{
Pair pair = new Pair();
int index = 0;
pair.Position = new List<int>();
foreach (int j in inputArray)
{
if (i == j)
{
pair.Position.Add(index);
}
index++;
}
pair.Number = i;
pairList[pairIndex] = pair;
pairIndex++;
}
return pairList;
}
Pair[] pairs = NewCollection.GetIndex(array, intQuery);
List<int> minWindow = new List<int>();
for (int i = 0; i <pairs.Length - 1; i++)
{
List<int> first = pairs[i].Position;
List<int> second = pairs[i + 1].Position;
int? temp = null;
int? temp1 = null;
foreach(int m in first)
{
foreach (int n in second)
{
if (n > m)
{
temp = m;
temp1 = n;
}
}
}
if (temp.HasValue && temp1.HasValue)
{
if (!minWindow.Contains((int)temp))
minWindow.Add((int)temp);
if (!minWindow.Contains((int)temp1))
minWindow.Add((int)temp1);
}
else
{
Console.WriteLine(" Bad Query array");
minWindow.Clear();
break;
}
}
if(minWindow.Count > 0)
{
Console.WriteLine("Minimum Window is :");
foreach(int i in minWindow)
{
Console.WriteLine(i + " ");
}
}
void findMinWindow(const vector<int>& input, const vector<int>& query) {
map<int, int> qtree;
for(vector<int>::const_iterator itr=query.begin(); itr!=query.end(); itr++) {
qtree[*itr] = 0;
}
int first_ptr=0;
int begin_ptr=0;
int index1 = 0;
int queptr = 0;
int flip = 0;
while(true) {
//check if value is in query
if(qtree.find(input[index1]) != qtree.end()) {
int x = qtree[input[index1]];
if(0 == x) {
flip++;
}
qtree[input[index1]] = ++x;
}
//remove all nodes that are not required and
//yet satisfy the all query condition.
while(query.size() == flip) {
//done nothing more
if(queptr == input.size()) {
break;
}
//check if queptr is pointing to node in the query
if(qtree.find(input[queptr]) != qtree.end()) {
int y = qtree[input[queptr]];
//more nodes and the queue is pointing to deleteable node
//condense the nodes
if(y > 1) {
qtree[input[queptr]] = --y;
queptr++;
} else {
//cant condense more just keep that memory
if((!first_ptr && !begin_ptr) ||
((first_ptr-begin_ptr)>(index1-queptr))) {
first_ptr=index1;
begin_ptr=queptr;
}
break;
}
} else {
queptr++;
}
}
index1++;
if(index1==input.size()) {
break;
}
}
cout<<"["<<begin_ptr<<" - "<<first_ptr<<"]"<<endl;
}
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main() {
vector<int> input;
input.push_back(2);
input.push_back(5);
input.push_back(2);
input.push_back(8);
input.push_back(0);
input.push_back(1);
input.push_back(4);
input.push_back(7);
vector<int> query1;
query1.push_back(2);
query1.push_back(8);
query1.push_back(0);
vector<int> query2;
query2.push_back(2);
query2.push_back(1);
query2.push_back(7);
vector<int> query3;
query3.push_back(1);
query3.push_back(4);
findMinWindow(input, query1);
findMinWindow(input, query2);
findMinWindow(input, query3);
}