Мы не можем использовать ArrayList или что-то в этом роде, потому что учитель сказал нам не использовать их, поэтому я застрял на этом этапе. Сигнатура функции:

public static int[] deleteNth(int[] elements, int maxOccurrences){}

Я уже просматриваю массив и получаю длину скопированного int result[], который я верну, но теперь я застрял, думая, как я могу вставить определенные элементы. Я написал ввод-вывод метода:

deleteNth(new int[] {20,37,20,21}, 1) // return [20,37,21]
deleteNth(new int[] {1,1,3,3,7,2,2,2,2}, 3) // return [1, 1, 3, 3, 7, 2, 2, 2]

В последний шанс для меня я пробую что-то вроде этого, но мои мозги выгорают

for(int n:result) {
 int n1=0;
 boolean nope=false;
 for(;n1<elements.length;) {
  //TODOthings
 }
 result[n]=elements[n1];
} 

Для тех, кто мне не верит, вот мой код:

public static int[] deleteNth(int[] elements, int maxOccurrences) {
        int[] result = null;
        if (elements != null && maxOccurrences > 0) {
            int result_lenght=elements.length;
            int ocurrences=0;
            for(int n:elements) {
                for(int n1:elements) {
                    if(n==n1 && ocurrences!=maxOccurrences) {
                        ocurrences++;
                        result_lenght--;
                    }
                }
            }
            result=new int[result_lenght];
            for(int n:result) {
                int n1=0;
                boolean nope=false;
                for(;n1<elements.length;) {
                    //todothings
                }
                result[n]=elements[n1];
            }
        }else {
            result=elements;
        }
        return result;
    }
1
Varo95 16 Янв 2021 в 23:55

3 ответа

Лучший ответ

Возможное простое решение (хотя и неэффективное) - начать с создания метода, который принимает в качестве параметра массив, количество элементов в нем и значение и возвращает количество раз, когда значение появляется в массиве, что-то вроде :

int total_occurences(int[] elements, int size, int value) 

Используйте этот метод в своем основном коде:

int copy[] = new int [elements.length];
int elements_copied = 0;
for(int i = 0; i < elements.length; i++) {
    // Check if you are "allowed" to copy the element
    if(total_occurences(copy, elements_copied , value <= maxOccurrences){
      copy[elements_copied] = element[i];
      elements_copied ++;
    }          
}
// copy the content to a new array of size = elements_copied
// return that array

Основная идея состоит в том, чтобы сначала создать массив ( т.е. int copy[] = new int [elements.length]) того же размера, что и массив elements, поскольку вы заранее не знаете, сколько существует дубликатов. Выполните итерацию по массиву elements и для текущего элемента ( т.е. element[i]) проверьте, скопировано ли уже (этот элемент) максимально допустимое число ( т.е. maxOccurrences):

if(total_occurences(copy, elements_copied , value <= maxOccurrences)

Если не скопировать элемент и увеличить количество скопированных элементов:

 copy[elements_copied] = element[i];
 elements_copied ++;

Нам нужно использовать другую переменную для итерации по массиву copy, поскольку он может содержать другое количество элементов, чем массив elements. Например, после того, как дублированный номер был "удален" . В конце вы можете создать новый массив (тот, который будет возвращен) с размером, равным переменной elements_copied, и скопировать элементы из массива copy в этот вновь созданный массив. Таким образом вы вернете массив без пропущенных значений в конце.

0
dreamcrash 16 Янв 2021 в 21:28

Поскольку никакие библиотечные средства, такие как Set или Map, и соответствующие реализации не могут быть использованы в этой задаче, и повторное изобретение колес для повторной реализации этих классов кажется гораздо более сложным, чем необходимо, простое решение может быть основано на использовании объектной оболочки Integer для int, чтобы использовать null для отметки значений, которые должны быть удалены.

Итак, алгоритм будет следующим:

  1. Преобразовать ввод int[] в Integer[]
  2. Инициализируйте nullCount, используя вложенные циклы, обнаружите повторяющиеся значения, превышающие порог, и установите их на null вместе с увеличением nullCount
  3. Создайте массив результатов, скопируйте ненулевые значения и верните его.

Пример реализации:

public static int[] deleteNth(int[] elements, int maxOccurrences) {
    Integer[] arr = new Integer[elements.length];
    int i = 0;
    for (Integer x : elements) {
        arr[i++] = x;
    }
    
    int nullCount = 0;
    for (i = 0; i < arr.length; i++) {
        Integer x = arr[i];
        if (null == x) {
            continue;
        }
        int cnt = 1;
        for (int j = i + 1; j < arr.length; j++) {
            Integer y = arr[j];
            if (null == y) {
                continue;
            }
            if (x.equals(y)) {
                cnt++;
                if (cnt > maxOccurrences) {
                    arr[j] = null;
                    nullCount++;
                }
            }
        }
    }
    int[] result = new int[arr.length - nullCount];
    i = 0;
    for (int j = 0; j < arr.length; j++) {
        Integer x = arr[j];
        if (null != x) {
            result[i++] = x;
        }
    }
    return result;
}

Тест и вывод:

System.out.println(Arrays.toString(deleteNth(new int[] {20,37,20,21}, 1))); // return [20,37,21]
System.out.println(Arrays.toString(deleteNth(new int[] {1,1,3,3,7,2,2,2,2}, 3))); // return [1, 1, 3, 3, 7, 2, 2, 2]

Выход:

[20, 37, 21]
[1, 1, 3, 3, 7, 2, 2, 2]

Более быстрая версия может использовать дополнительный логический массив для отслеживания повторяющихся значений, чтобы их можно было пропустить во вложенном цикле.


Решение на основе потока (только для справки и сравнения) будет таким:

  • подготовить начальную карту с элементами массива в качестве ключей, а значение - список индексов, используя Collectors.groupingBy
  • переназначить записи в исходной карте: index -> key (элемент массива) с помощью flatMap и Stream::limit для соблюдения порогового значения
  • отсортировать новые записи по индексу
  • получить значения и собрать их в массив
public static int[] deleteNth(int[] arr, int threshold) {
    return IntStream
            .range(0, arr.length)
            .boxed()
            .collect(Collectors.groupingBy(
                i -> arr[i], 
                Collectors.mapping(i -> i, Collectors.toList())
            ))
            .entrySet()
            .stream()
            .flatMap(e -> e.getValue().stream()
                    .limit(threshold)
                    .map(ix -> Map.entry(ix, e.getKey())) // Map.entry since Java 9
            )
            .sorted(Map.Entry.comparingByKey())
            .mapToInt(Map.Entry::getValue)
            .toArray();
}
1
Alex Rudenko 16 Янв 2021 в 23:15

Вы можете сделать это с помощью HashMap, чтобы отслеживать количество появлений каждого числа:

public static int[] deleteNth(int[] elements, int maxOccurrences){
    // get number of occurrences of each number in elements less than max
    Map<Integer,Integer> occurences = new HashMap<>();
    for(int element : elements) {
        int count = occurences.containsKey(element) ? occurences.get(element) : 0;
        if(count < maxOccurrences) occurences.put(element, count+1);
    }
    // calculate total size of array to return
    int size = 0;
    for(int numberOccurences : occurences.values()) size += numberOccurences;
    int[] res = new int[size];
    // clear map to reuse it
    occurences.clear();
    // reiterate over elements array
    int i = 0;
    for(int element : elements) {
        int count = occurences.containsKey(element) ? occurences.get(element) : 0;
        // add number to resulting array if its count in it is still less than max
        if(count < maxOccurrences) res[i++] = element;
        occurences.put(element, count+1);
    }
    return res;
}
0
Majed Badawi 16 Янв 2021 в 21:39
65754619