У меня есть список некоторых элементов.
List<Integer> list = new ArrayList<Integer>();
Предположим, что список содержит значения, как показано ниже:
0,0,0,0,0,1,1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4
Как добавить фиктивный элемент (например, -1) в качестве разделителя перед каждой из групп? результат должен быть
-1,0,0,0,0,0,-1,1,1,1,1,-1,2,2,2,2,2,-1,3,3,3,3,3,3,3,3,-1,4,4,4,4,4,4,4
Как мне это сделать эффективно?
РЕДАКТИРОВАТЬ
Способ 1:
Переопределив функцию add().
List<Integer> list = new ArrayList<Integer>(){
public boolean add(Integer add){
if(super.size()==0 || super.get(super.size()-1)!=add)
super.add(-1);
super.add(add);
return true;
}
};
Теперь list.add(number);
переопределит функцию добавления и добавит другое целое число (например, -1), когда оно обнаружит изменение значения из последнего элемента.
Способ 2
Традиционно. Iterate Over и добавьте -1
когда обнаружено изменение.
List<Integer> list = new ArrayList<Integer>();
list.addAll(Arrays.asList(0,0,0,0,0,1,1,1,1,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4));
int last=-1;
for(int i=0;i<list.size();i++){
if(list.get(i)!=last){
last=list.get(i);
list.add(i, -1);
++i;
}
}
Вам просто нужно отслеживать предыдущие значения и перебирать список.
List<Integer> origList = getListHowever();
List<Integer> spacedList = new ArrayList<Integer>();
int bufferElement = -1;
int currVal;
int lastVal = Integer.MIN_VALUE; // or some default value that is unlikely to be in the list
for (int i=0; i<origList.size(); i++) {
currVal = origList.get(i);
if (lastVal != currVal) {
spacedList.add(bufferElement);
}
spacedList.add(currVal);
lastVal = currVal;
}
Та же методология может быть выполнена, поскольку элементы добавляются в исходный список. Следите за последним добавленным значением или загляните в последний элемент.
int curVal = origList.get(i);
и, ссылаясь на это, теперь вы выполняете origList.get(i)
3 раза в каждом цикле.
Здесь мое решение, если повторяющиеся целые числа сортируются.
Пример сортированных повторяющихся целых чисел:
0,0,0,1,1,1,2,2,3,3,3,3,4,4,4
Код
class FrequencyOrderedSet
{
LinkedHashMap<Integer,Integer> list;
public FrequencySet()
{
list = new LinkedHashMap<Integer,Integer> ();
}
public void insert (Integer number)
{
if (list.constainsKey(number))
list.put(number, list.get(number)+1);
else
list.put(number, 1);
}
public void remove (Integer number)
{
if (list.containsKey(number))
if (list.get(number) > 1)
list.put(number, list.get(number)-1);
else
list.remove(number);
}
public ArrayList getList ()
{
ArrayList out = new ArrayList<Integer> ();
for (Integer num : list.getKeyList())
for (int i=0; i<list.get(num); i++)
out.add(num);
}
}
Используйте Linked hash map, сделайте для цикла по массиву, поместите число как ключ и частоту в качестве значения. Нет необходимости устанавливать разделители вообще.
Если вам нужно знать только значение и количество элементов в каждой группе, вы можете использовать два массива. Например, если у вас есть n разных разных значений (или n group), вы можете иметь значение массива int[] value
и int[]count
со value[i]
- значение i-й группы, а count[i]
- это число элемента в i-й группе.
Итак, в вашем случае:
int [] value = new int[5];
int [] count = new int[5];
value[0] = 0;
count[0] = 5;
value[1] = 1;
count[1] = 4;
......
Чтобы преобразовать из list
в value
и count
, вам просто нужно выполнить два бинарных поиска для поиска начальных и конечных индексов определенного значения в list
(если list
отсортирован). Таким образом, временной сложностью будет O (nlog m), где m - размер list
.
Как упоминает Зойд в своем комментарии, мы также можем использовать HashMap <Integer,Integer>
для хранения значения и числа пар элементов или TreeMap<Integer, Integer>
для сохранения упорядоченных заказов.