Я нашел этот вопрос в leetcode, так как сейчас изучаю массивы. Похоже, проблема в блоке shifting данного кода.
Example 1:
Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]
Example 2:
Input: nums = [-1,-100,3,99], k = 2
Output: [3,99,-1,-100]
Explanation:
rotate 1 steps to the right: [99,-1,-100,3]
rotate 2 steps to the right: [3,99,-1,-100]
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = sizeof(nums)/sizeof(nums[0]);
k = k%n;
vector<int> temp;
//storing the elements of the array till k places
for(int i = 0; i < k; i++) {
temp.push_back(nums[i]);
}
//shifting by k places
for(int i = k; i<n;i++) {
nums[i+k] = nums[i];
}
//putting the temp back to the place
int j = 0;
for(int i = n-k; i < n; i++) {
nums[i] = nums[j];
j++;
}
}
};
Я решил повернуть массив, оставленный на k мест, в моем локальном редакторе. Я прекрасно понимаю решение.
Здесь, насколько я знаю, происходит переполнение памяти.
Я уверен, что остальная часть кода работает нормально, за исключением блока shifting.
Вы должны определить int n = nums.size(); + что, по вашему мнению, происходит, например. вектор размера 10 с k = 5 в цикле for(int i = k; i<n;i++)? Представьте себе, что когда i равно 9, то nums[i+k] все еще находится внутри вектора?
sizeof(nums)/sizeof(nums[0]) предназначен для массивов C, а не std::vector. Для std::vector используйте для этого метод size().
См. std::rotate.
If (k < size(vec)) std::rotate(begin(vec), begin(vec)+k, end(vec)); и получайте удовольствие. Не забудьте #include <algorithm>.
@Red.Wave Я думаю, вы пропустили, что ОП призывает к повороту вправо. std::rotate выполняет операцию поворота влево. Поскольку ОП требует поворота вправо, если вы собираетесь использовать std::rotate, вам придется использовать begin(vec) + (vec.size() - k) в качестве среднего аргумента.
@tbxfreeware Для поворота влево и вправо используйте обратные итераторы: std::rotate(rbegin(vec), rbegin(vec)+k, rend(vec));.
Похоже, проблема заключается в блоке сдвига данного кода. Это однострочное решение, уже решенное с помощью std::rotate. Посмотрите это
Я нашел этот вопрос в leetcode, поскольку сейчас изучаю массивы. Leetcode не учит вас C++. По сути, это набор случайных вопросов-головоломок для людей, которые уже имеют опыт работы с языком, который они будут использовать для решения головоломки. Он не предназначен для начинающих программистов — если вы только начинаете изучать массивы, тратить время на решение головоломок, ориентированных на опытных программистов, не поможет. Кроме того, вопросы Leetcode разработаны таким образом, что «грубая сила» почти никогда не сработает при заданных ограничениях, и необходимо использовать более сложные подходы.





Предположим, ваш вектор имеет длину 5 элементов, вы делаете правильный int n = nums.size();, а затем хотите повернуть на k=3.
В вашем цикле for, поскольку i == k и k == 3, ваша первая итерация затем обращается к num[3+3], который выходит за пределы и, следовательно, выходит из строя.
Чтобы правильно реализовать алгоритм вращения, вы должны учитывать размер массива во время итерации и корректировать свой индекс с помощью оператора по модулю внутри вашего цикла. Поскольку это обучающее упражнение, я не хочу сразу давать вам полное решение — но, возможно, этого уже достаточно, чтобы направить вас на правильный путь.
Ваш подход верен, но вы поменялись ролями k и n - k.
Как было объяснено в комментариях, вы также неправильно применили идиому языка C для определения размера массива — std::vector. std::vector несет в себе свой размер. Вы можете получить его, вызвав функцию-член size().
На первом этапе поместите первые элементы n - k в вектор temp.
На втором этапе скопируйте последние элементы k в начало вектора.
На последнем этапе скопируйте элементы n - k из временного вектора в конец вектора nums (начиная с нижнего индекса k).
При вашем подходе нет необходимости использовать оператор %.
Подстрочные индексы должны использовать тип std::size_t, который находится в заголовке <cstddef>. Следующая программа аккуратно приводит k к типу std::size_t и использует этот тип для всех переменных управления циклом.
// main.cpp
#include <cassert>
#include <cstddef>
#include <iostream>
#include <string_view>
#include <utility>
#include <vector>
// This using declaration allows the LeetCode Solution
// to be used without modifying its function signature.
//
// (Shame on you, LeetCode, for teaching programmers to
// rely on `using namespace std;`.)
using std::vector;
class Solution {
public:
void rotate(vector<int>& nums, int k) {
// Preconditions:
// `nums.size()` lies on the interval [0, 10^5]
// `k` lies on the interval [0, 10^5]
assert(nums.size() <= 100'000u);
assert(k >= 0 && k <= 100'000);
// Vector size (and subscripts) use type `std::size_t`, from
// header <cstddef>. Force `kk` to the half-open interval [0, n).
std::size_t const n{ nums.size() };
std::size_t const kk{ static_cast<std::size_t>(k) % n };
// Treat the "no-rotatation" circumstance as a special case.
if (kk == 0u)
return;
// Copy the first (n - kk) elements into a temporary vector.
vector<int> temp;
for (std::size_t i{}; i < (n - kk); ++i) {
temp.push_back(nums[i]);
}
// Copy the last kk elements to the front of the vector.
std::size_t from{ n - kk };
for (std::size_t i{}; i < kk; ++i)
nums[i] = nums[from++];
// Copy (n - kk) elements from the temporary vector to the
// end of vector nums (beginning with subscript `kk`).
from = 0u;
for (std::size_t i{ kk }; i < n; ++i)
nums[i] = temp[from++];
}
};
class put_vector
{
std::vector<int> const& v;
public:
put_vector(std::vector<int> const& v) : v(v) {}
friend std::ostream& operator<< (std::ostream& ost, put_vector const& pv) {
ost.put('[');
if (!pv.v.empty()) {
ost << pv.v.front();
for (std::size_t i{ 1u }; i < pv.v.size(); ++i)
ost << ',' << pv.v[i];
}
ost.put(']');
return ost;
}
};
void solve(
std::string_view heading,
std::vector<int> nums,
int k)
{
std::cout
<< heading
<< '\n'
<< "\n Input: nums = " << put_vector(nums) << ", k = " << k;
Solution{}.rotate(nums, k);
std::cout
<< "\n Output: " << put_vector(nums)
<< "\n\n";
}
int main() {
std::cout << "LeetCode 189. Rotate Array"
"\nhttps://leetcode.com/problems/rotate-array/"
"\n\n";
solve("Example 1", { 1,2,3,4,5,6,7 }, 3);
solve("Example 2", { -1,-100,3,99 }, 2);
}
// end file: main.cpp
Вывод соответствует примерам с сайта LeetCode.
LeetCode 189. Rotate Array
https://leetcode.com/problems/rotate-array/
Example 1
Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Example 2
Input: nums = [-1,-100,3,99], k = 2
Output: [3,99,-1,-100]
std::copyВ комментариях ниже @Evg указывает, что векторные элементы можно копировать с помощью std::copy (и итераторов). Я избегал использования вышеперечисленных, потому что хотел остаться в стиле ФП. Однако если они вас устраивают, программу можно значительно упростить.
std::copy позволяет удалить циклы, и вместе с ними полученный код легче читать и легче поддерживать.
Как показано ниже, std::copy принимает три аргумента, каждый из которых является итератором. Первые два описывают диапазон копирования: [первый, последний). Третий определяет пункт назначения.
// Copy the first (n - k) elements into a temporary vector.
auto const nk{ n - k };
vector<int> temp(nk);
std::copy(nums.cbegin(), nums.cbegin() + nk, temp.begin());
// Copy the last k elements to the front of the vector.
std::copy(nums.cbegin() + nk, nums.cend(), nums.begin());
// Copy (n - k) elements from the temporary vector to the
// end of vector `nums` (beginning with subscript `k`).
std::copy(temp.cbegin(), temp.cend(), nums.begin() + k);
Как предложил @Jarod42, использование std::rotate сводит это к одной строке.
Вам не нужны все эти циклы для копирования элементов. Просто используйте пары итераторов.
Согласованный. Я пытался оставаться в рамках стиля, используемого ОП. ;)
Чтобы решить эту проблему более эффективно, используйте следующий трюк:
void reverse(std::vector<int>& nums, int start, int end), которая работает за временную сложность O(n/2).Готово, вектор сдвигается на k элементов.
int n = sizeof(nums)/sizeof(nums[0]);максимально неправильно.