Вопрос или проблема
Дана массив
arr
, верните второй по величине уникальный элемент из массива. Если второго по величине элемента не существует, верните -1.
Я пытался найти второй по величине элемент в массиве. Может кто-нибудь объяснить, где я ошибся?
int getSecondLargest(vector<int> &arr) {
// Код здесь
int max = 0;
int smax = 0;
int ans = -1;
for(int i =0; i<arr.size(); i++){
if(arr[i]>max){
max = arr[i];
}
}
for(int i =0; i<arr.size(); i++){
if(arr[i]<max){
smax = arr[i];
}
}
for(int i=0; i<arr.size(); i++){
if(arr[i]>smax && arr[i]<max){
smax = arr[i];
}
}
if(max != smax){
return smax;
}
if(max == smax){
return ans;
}
}
Здесь код не дает никакого вывода, когда в массиве нет второго по величине элемента.
int getSecondLargest(vector<int> &arr) {
if(arr.size() < 2) return -1;
int max = INT_MIN, smax = INT_MIN;
for(int i = 0; i < arr.size(); i++) {
if(arr[i] > max) {
smax = max;
max = arr[i];
} else if(arr[i] > smax && arr[i] < max) {
smax = arr[i];
}
}
return (smax == INT_MIN) ? -1 : smax;
}
Пройдите по массиву один раз. Если arr[i] больше max, обновите и max, и smax. Если arr[i] находится между smax и max, обновите smax. Если второго уникального по величине элемента не существует, верните -1.
Вам нужно инициализировать максимальное значение минимально возможным значением для используемого типа, поэтому вы можете использовать std::numeric_limits<int>::min()
Этот участок кода вернет это значение, если второго максимума нет:
#include <vector>
#include <limits>
#include <iostream>
using namespace std;
int getSecondLargest (vector<int> const& arr)
{
// Код здесь
int max = std::numeric_limits<int>::min();
int smax = std::numeric_limits<int>::min();
for(int i =0; i<arr.size();i++)
{
if (arr[i]>max) { max = arr[i]; }
}
for(int i =0; i<arr.size(); i++)
{
if (arr[i]>smax and arr[i]<max) { smax = arr[i]; }
}
return smax;
}
int main()
{
cout << getSecondLargest ({ 1,2,3,4,5,6,7 }) << "\n";
cout << getSecondLargest ({ 7,6,5,4,3,2,1 }) << "\n";
cout << getSecondLargest ({ 4,5,6,1,2,9,0 }) << "\n";
cout << getSecondLargest ({ 7,7 }) << "\n";
cout << getSecondLargest ({ }) << "\n";
}
Вместо готового решения я предложу идею о том, как решить это с помощью итераторов.
- Начните с того, чтобы сделать два итератора (здесь называемых
largest
иsecond
) и укажите их на первые два уникальных элемента. Если не найдено два уникальных элемента, верните итераторend
. - Пройдите по оставшемуся диапазону в поисках элементов, больших чем второй по величине, найденный на данный момент, и замените соответствующий итератор.
template <class It>
It getSecondLargest(It begin, It end) {
if (begin == end) return end; // нет элементов, верните итератор end
auto largest = begin;
// ищем первый элемент, не равный *largest:
do {
++begin;
if (begin == end) return end; // не найден такой элемент
} while (*begin == *largest);
auto second = begin;
// меняем их местами, если необходимо:
if (*largest < *second) std::swap(second, largest);
// проверяем, есть ли другие большие элементы
for (++begin; begin != end; ++begin) {
if (*second < *begin) {
if (*largest < *begin) { // еще больше?
second = largest; // второй теперь ранее наибольший
largest = begin; // и у нас новый наибольший
} else if (*begin < *largest) { // не дубликат наибольшего?
second = begin; // тогда у нас новый второй по величине
}
}
}
return second;
}
Ответ или решение
Чтобы решить задачу нахождения второго по величине уникального элемента в массиве, необходимо учесть несколько важных аспектов. Приведенная ниже реализация учитывает возможность отсутствия второго по величине элемента и возвращает -1
в таких случаях.
Решение
Алгоритм
- Проверка на пустоту: Если массив содержит меньше двух элементов, вернуть
-1
, так как второго максимума не может быть. - Инициализация: Используем переменные для хранения максимального (
max
) и второго максимального (smax
) значения. Инициализируем их минимально возможными значениями для целого типаint
, используяstd::numeric_limits<int>::min()
. - Перебор элементов массива:
- Если текущий элемент больше, чем
max
, мы обновляемsmax
значениемmax
, аmax
– текущим элементом. - Если текущий элемент находится между
smax
иmax
, обновляемsmax
текущим элементом.
- Если текущий элемент больше, чем
- Проверка на существование второго максимального элемента: Если
smax
после завершения проверки остается равнымstd::numeric_limits<int>::min()
, возвращаем-1
, указывая на отсутствие второго максимума. - Возврат результата: Если всё прошло успешно, возвращаем значение
smax
.
Код на C++
#include <vector>
#include <limits>
#include <iostream>
using namespace std;
int getSecondLargest(const vector<int>& arr) {
if (arr.size() < 2) return -1; // Если массив содержит менее 2 элементов, возврат -1.
int max = numeric_limits<int>::min();
int smax = numeric_limits<int>::min();
for(int i = 0; i < arr.size(); i++) {
if (arr[i] > max) {
smax = max; // Обновляем второй максимум.
max = arr[i]; // Обновляем максимум.
} else if (arr[i] > smax && arr[i] < max) {
smax = arr[i]; // Обновляем второй максимум, если элемент между max и smax.
}
}
return (smax == numeric_limits<int>::min()) ? -1 : smax; // Если нет второго максимума, возврат -1.
}
int main() {
cout << getSecondLargest({1, 2, 3, 4, 5, 6, 7}) << "\n"; // Ожидаем 6
cout << getSecondLargest({7, 6, 5, 4, 3, 2, 1}) << "\n"; // Ожидаем 6
cout << getSecondLargest({4, 5, 6, 1, 2, 9, 0}) << "\n"; // Ожидаем 6
cout << getSecondLargest({7, 7}) << "\n"; // Ожидаем -1
cout << getSecondLargest({}) << "\n"; // Ожидаем -1
}
Примечания
- Этот подход использует один проход по массиву, что делает его эффективным с точки зрения времени выполнения – O(n), где n – количество элементов в массиве.
- Важно правильно обрабатывать случаи, когда массив содержит все одинаковые элементы или его длина меньше двух. В этих случаях алгоритм корректно вернет
-1
.
Заключение
Таким образом, предложенное решение обеспечивает корректный поиск второго по величине элемента, а также эффективно обрабатывает случаи, когда такого элемента не существует. Учитывая единственный проход по массиву, данное решение оптимально по времени и прекрасно подходит для большинства практических применений.