2016-09-20 73 views
-2

我有一个方法,它从包含A,C,G,T字母组的输入字符串中寻找最小的substring原始HashMap被修改

我的问题与算法无关。

我想保持原来的HashMap并指定为修改后的地图在外部for循环的结束,但原来HashMap被修改,即使我从来不修改代码的originalMap

我不知道我是否做错了。

代码

void find2(String string) { 
    int n = string.length(); 
    int occurrence = n/4; 
    Map<Character, Integer> cache = new HashMap<Character, Integer>(); 
    char[] original = { 'A', 'C', 'G', 'T' }; 
    for (char c : original) { 
     cache.put(c, 0); 
    } 
    char[] chars = string.toCharArray(); 
    char[] modifiableChars = string.toCharArray(); 

    HashMap<Character, Integer> countMap = new HashMap<Character, Integer>(); 
    for (int ii = 0; ii < string.length(); ii++) { 
     char currentChar = chars[ii]; 
     if (!countMap.containsKey(currentChar)) { 
      countMap.put(currentChar, 1); 
     } else { 
      Integer count = countMap.get(currentChar); 
      count++; 
      countMap.put(currentChar, count); 
     } 
    } 
    HashMap<Character, Integer> map = new HashMap<Character, Integer>(); 
    HashMap<Character, Integer> originalMap = new HashMap<Character, Integer>(); 
    for (int ii = 0; ii < string.length(); ii++) { 
     char c = string.charAt(ii); 
     if (!map.containsKey(c)) { 
      map.put(c, 1); 
     } else { 
      Integer count = map.get(c); 
      count++; 
      map.put(c, count); 
     } 
     if (!originalMap.containsKey(c)) { 
      originalMap.put(c, 1); 
     } else { 
      Integer count = originalMap.get(c); 
      count++; 
      originalMap.put(c, count); 
     } 
    } 
    int min = 0; 
    for (int i = 0; i < chars.length; i++) { 
     int change = 0; 

     int checkCount = countMap.get(chars[i]); 
     if (checkCount <= occurrence) { 
      continue; 
     } 



     boolean isValidated = false; 
     int j = i; 
     for (j = i; j < chars.length; j++) { 
      char c = chars[j]; 
      int count = map.get(c); 
      if (count > occurrence) { 

      } 
      char nextChar = getNextChar(map, cache, occurrence); 
      if (nextChar == ' ') { 
       continue; 
      } 
      Integer nextCharCount = map.get(nextChar); 
      nextCharCount++; 
      map.put(nextChar, nextCharCount); 
      chars[j] = nextChar; 

      if (c != nextChar) { 
       Integer currentCount = map.get(c); 
       currentCount--; 
       map.put(c, currentCount); 
      } 

      change++; 
      // validate the characters. 
      if (isValid(chars, occurrence)) { 
       isValidated = true; 
       break; 
      } 
     } 
     if (isValidated) { 
      if (min == 0) { 
       min = change; 
      } else { 
       min = Math.min(min, change); 
      } 
     } 
     chars = string.toCharArray(); 
     map = originalMap; // <-------- 
    } 
    System.out.println(min); 
} 
+0

'一个= someMap'不创建'someMap的副本“如果这是问题。如果您想要一个副本,请使用https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html#HashMap-java.util.Map- – 2016-09-20 05:51:15

+1

这段代码的要点是否应该这样做?你提到你没有修改'originalMap',但是我看到'originalMap.put(c,1);' –

+0

''HashMap originalMap = new HashMap ();”正在初始化原始地图以包含每个字母的原始计数,因为'地图'被修改。 – user826323

回答

0

我认为你应该做的

Map map = new HashMap(); // generic later 
map.putAll(originalMap); 

代替

map = originalMap; 

这只是改变了参考指向原来的HashMap中。所以在第二次迭代中修改了原始hashmap。你需要的是创建副本。

+0

啊..我明白为什么..谢谢。 – user826323

+0

请接受它作为答案。如果它解决了问题 – Suraj

+1

如果'map'超过'originalMap'超过一些额外的条目。一开始会抛弃它们吗?不,它不会。在'putAll'操作之后,您可能会也可能不会有意外的输入。所以,这不是一个安全的选择。 –

0

在最开始创建一个新的HashMap是原单的副本,而for循环内进入:

Map<SomeType, OtherType> map1 = new HashMap<SomeType, OtherType>(original); 

不推荐使用putAll,因为它不会放弃已经存在目标hashmap中的条目。 Demo

HashMap newmap1 = new HashMap(); 
    HashMap newmap2 = new HashMap(); 

    // populate hash map 
    newmap1.put(1, "tutorials"); 
    newmap1.put(2, "point"); 
    newmap1.put(3, "is best"); 
    newmap2.put(5, "Foo"); 

    System.out.println("Values in newmap1: "+ newmap1); 
    System.out.println("Values in newmap2: "+ newmap2); 
    newmap2.putAll(newmap1); 
    System.out.println("Values in newmap2: "+ newmap2); 

给出输出:

Values in newmap1: {1=tutorials, 2=point, 3=is best} 
Values in newmap2: {5=Foo} 
Values in newmap2: {1=tutorials, 2=point, 3=is best, 5=Foo} 

正如你所看到的条目{5, "Foo"}使用putAll,这是不希望当你想恢复到原来hashmap后保持完整

编辑:

为,它是suggested to avoid地图实例创建尽可能在for循环的末尾使用.clear() + .putAll()操作。

0

其中在循环的开始与原地图的副本创建map其他的答案是更好,但将现有的逻辑:

map = originalMap; // <-------- 

应该成为

map.clear(); 
    map.putAll(originalMap); 

而且几个提示:

HashMap<Character, Integer> countMap = new HashMap<Character, Integer>(); 

可以成为更抽象的Map,并且推断类型<>

Map<Character, Integer> countMap = new HashMap<>(); 

与Java 8:

if (!countMap.containsKey(currentChar)) { 
     countMap.put(currentChar, 1); 
    } else { 
     Integer count = countMap.get(currentChar); 
     count++; 
     countMap.put(currentChar, count); 
    } 

可以成为一衬垫

countMap.merge(currentChar, 1, Integer::add); 
        =========== = ============ 
        |   |  | 
        |   | function(old, 1) when old value exists 
        |   | returns new value or null to delete 
        |   | 
        |   new value when no value (or null value) 
        key 
+0

这是我找到C++方便的地方,只要做'++ mymap [key]',一切都很好。 :) –

+0

@SauravSahu是别名,'int&',可以派上用场。 –