具有两个列表的最小连续子序列

时间:2018-02-18 21:25:31

标签: java algorithm oop

TargetList和AvailableTagsList是两个字符串列表。 TargetList将包含Distinct字符串对象。

Input:
TargetList = {"cat", "dog"};
AvailableTagsList = {"cat", "test", "dog", "get", "spain", "south"};
Output: [0, 2] //'cat' in position 0; 'dog' in position 2


Input:
TargetList = {"east", "in", "south"};
AvailableTagsList = {"east", "test", "east", "in", "east", "get", "spain", "south"};
Output: [2, 7] //'east' in position 2; 'in' in position 3; 
              //'south' in position 6 (east in position 4 is not outputted as it is coming after 'in')

Input:
TargetList = {"east", "in", "south"};
AvailableTagsList = {"east", "test", "south"};
Output: [0] //'in' not present in availableTagsList

我将AvailableTags中显示的字词位置存储到listMap

Map<String, List<Integer>> listMap = new HashMap<>();
int counter = 0;
for(String availableItem : AvailableTagsList) 
{
    if(listMap.containsKey(availableItem))
        listMap.get(availableItem).add(counter);
    else 
    {
        List<Integer> temp = new ArrayList<>();
        temp.add(counter);
        listMap.put(availableItem, temp);
    }
    counter++;
}

我将listMap中的所有元素列表添加到resultList

listMap will be like 
"east" - [0,2,4] 
"in" - [3] 
"south" - [7] 

resultList will have like [0,2,4,3,7] 

我能用什么来解决这个问题,使用resultList如何显示AvailableTagsList中的最小子序列?我使用正确的方法吗?到目前为止我的进展情况如何?有没有其他替代方法来解决这个问题。

3 个答案:

答案 0 :(得分:2)

我不知道该问题的最佳解决方案,但根据您的想法

  • 从TargetList中获取每个单词的位置 AvailableTagsList(请注意它们将被排序),例如 目标列表和可用列表为:TargetList = {“ east”,“ in”, “ south”} AvailableTagsList = {“东部”,“测试”,“东部”,“中”,“东部”, “ get”,“ spain”,“ south”}因此,在此步骤之后,我将向东走: 0,2,4于:3南:7
  • 现在:我知道我可以有3个正确的起点吗?为了第一 我的起始单词p0的位置,我可以找到单词的位置p1 (i + 1)使得p1> p0 ??如果是,我可以为 word(i + 2)这样p2> p1等等,直到找到所有目标列表。 我怎样才能做到这一点 ?如果我知道位置p1,我需要找到 第一个p2使得p2> p1?我可以使用二进制搜索来做到这一点吗? 是的,因为所有数组都已排序。这是代码
public class MinimumCtsSubsequence {

    static String[] words, tags;

    public static void main(String[] args) {
        words = new String[] { "east", "in", "south" };
        tags = new String[] { "east", "test", "east", "in", "east", "get", "spain", "south" };
        ArrayList<Integer> ans = minSubSequence();
        for (int i = 0; i < ans.size(); ++i) {
            System.out.print(ans.get(i) + " ");
        }

    }

    static ArrayList<Integer> minSubSequence() {
        ArrayList<Integer>[] occur = new ArrayList[words.length];
        for (int i = 0; i < words.length; ++i)
            occur[i] = new ArrayList<Integer>();
        HashMap<String, Integer> indices = new HashMap<String, Integer>();
        for (int i = 0; i < words.length; ++i) {
            indices.put(words[i], i);
        }
        for (int i = 0; i < tags.length; ++i) {
            String tag = tags[i];
            if (indices.containsKey(tag)) {
                int wordI = indices.get(tag);
                occur[wordI].add(i);
            }
        }
        // till now comp is o(n)
        // loop throught all the starts that we have
        int ans = Integer.MAX_VALUE;
        int s1 = 0, e1 = 0;
        for (int i = 0; i < occur[0].size(); ++i) {
            int start = occur[0].get(i);
            boolean poss = true;
            int next = 0;
            for (int j = 1; j < words.length; ++j) {
                next = getNextGreater(start, occur[j]);
                if (next == -1) {
                    poss = false;
                    break;
                }
            }
            if (poss && ans > next - start) {
                s1 = start;
                e1 = next;
                ans = next - start;
            }

        }
        ArrayList<Integer> solu = new ArrayList<Integer>();

        if (ans == Integer.MAX_VALUE) {
            solu.add(0);
            return solu;
        }

        solu.add(s1);
        solu.add(e1);

        return solu;
    }

    static int getNextGreater(int x, ArrayList<Integer> arr) {
        int start = 0;
        int end = arr.size() - 1;
        int ans = -1;
        while (start < end) {
            int mid = (start + end) / 2;
            if (arr.get(mid) <= x) {// go right
                start = mid + 1;
            } else {
                ans = arr.get(mid);
                end = mid;
            }

        }
        if (start == end && arr.get(start) > x)
            return arr.get(start);
        return ans;
    }

答案 1 :(得分:0)

我倾向于将事物视为图形问题,因此我将其视为图形问题*。在完成您已经完成的列表映射步骤之后,您可以构建一个图形,最终找到最短路径。

  • 创建一个将成为源的节点S.
  • 制作一个将成为目的地的节点D.
  • 为您关注的每个字词添加节点,确保您知道它们的位置。
  • 从源添加边缘到权重为0的每个匹配项(因为您可以从任何这些开始)。
    • 对于您的示例,这些将​​是:
      • east0
      • east2
      • east4
      • 立方英寸
      • south7
  • 将每个最终单词的边添加到dest,权重为0(再次,您可以完成其中任何一个)
  • 对于目标列表中的每对相邻单词(w1,w2)[例如你的例子中的(east,in),(in,south):
    • 为每个节点添加w1到w2的每个节点的边缘,其中w2的节点的位置大于w1的节点,其权重等于其位置的差值。 **
    • 以您的示例为例,这些边缘:
      • east0 - &gt; in3,体重3
      • east2 - &gt; in3,重量1
      • in3 - &gt; south7,重量4
  • 现在您已经使用任何方法找到从S到D的最短路径(例如Djikstra算法)

因为你想要开始和结束的位置,你需要跟踪哪些节点形成最短的路径,以及它们来自哪个位置,以便你可以返回这些节点&#39;位置。这是一种非常典型的最短路径算法扩充,可能的例子和指导可以在互联网上找到。

*我不主张这必然是一个不错的选择,或者是最快或最简单的选择,但它会起作用。

**这里有一个优化,你可以让每个w1节点都有一个到下一个w1节点的边缘,每个w1节点只连接到位置大于它的最近的w2节点。 / p>

有几个小时的时间来考虑这个,我很确定你可以在O(n)时间和空间中这样做(使用优化的图形,并从输入中仔细构建它)。所以它至少不会非常缓慢。

答案 2 :(得分:0)

一种方法是不合并初始问题中提供的那些列表。

您必须意识到范围只会受到第一个和最后一个标记的索引的影响。中间发生的事情不会真正影响范围(如果确实存在)。

话虽如此,对于任何有效的解决方案都需要有两个约束条件。

如果每个标签都有一个索引列表,那么如果从左侧按顺序从每个标签移动:

  • 在'当前标签'中找到的索引必须在'下一个标签'中有更大的索引,依此类推,直到我们到达标签的末尾。

如果你从右边移动:

  • '当前标签'中的索引必须在'previous tag'中有较小的索引,因此直到我们到达标签的开头。

基本上,你试图从两端缩小。

如果您无法满足这些约束条件,那么您就知道没有有效的解决方案。

我不知道这是否是最佳解决方案或方法。但它会起作用。