Inaccuracy in code which returns the next permutation of an array - c++

I was solving a question on leetcode with the description:
The next permutation of an array of integers is the next lexicographically greater permutation of its integer. More formally, if all the permutations of the array are sorted in one container according to their lexicographical order, then the next permutation of that array is the permutation that follows it in the sorted container. If such arrangement is not possible, the array must be rearranged as the lowest possible order (i.e., sorted in ascending order).
This is what I came up with in C++:
void nextPermutation(vector<int>& nums) {
int index = -1, j = nums.size() - 1;
for (int i = nums.size() - 1; i > 0; i--)
{
if(nums[i - 1] < nums[i])
{
index = i - 1;
break;
}
}
if(index == -1)
{
reverse(nums.begin(), nums.end());
return;
}
for (int i = nums.size() - 1; i >= index + 1; i--)
{
if(nums[i] > nums[index])
{
j = i;
}
break;
}
swap(nums[index], nums[j]);
reverse(nums.begin() + index + 1, nums.end());
}
Here I traversed the array from left to right and look for an element which is smaller than the element on its right(named it index), and then traversed it again looking for a number just bigger than the number before and swapped them and then reversed the array after index
This code works for the example cases but fails in a case where:
Input: [2,3,1]
MyOutput: [1,2,3]
Expected Output: [3,1,2]
I do not understand what I did wrong and everything should be working but its not.

Your issue is that the break statement in second loop is outside the if block.
if (nums[i] > nums[index])
{
j = i;
}
break; // <--------- this should be inside if
Putting it inside, gives the correct result.
if (nums[i] > nums[index])
{
j = i;
break;
}
Demo: https://godbolt.org/z/147We9c4q

Related

How to decide if an array is a permutation of 1-N in O(log N)?

A sequence of length n is called a permutation if it contains all integers from 1 to n exactly once.
Can you tell whether an array is a permutation in O(log N)?
You mean to tell, whether an array contains a permutation?
O(log N) is not enough: You need O(N) to read all elements.
O(N*log N) would be enough to sort the array, then it is trivial to tell whether it is a permutation in O(N).
You could update a histogram during each write into the array and also update a counter, how many histogram entries are exactly 1. This would cost O(1) for each update and O(1) for the actual test.
constexpr int N = 1000;
std::array<int, N> arr = {}; // zero-init
std::array<int, N + 1> hist = {}; // zero-init, we ignore element 0 and use elements 1..N
int counter = 0;
// writes arr[i] = newv in O(1)
void write(int i, int newv) {
if(i < 0 || i > N-1) // invalid index
return;
const int oldv = arr[i]; // read previous array entry
if(oldv > 0 && oldv <= N) { // decrease histogram
if(hist[oldv] == 1)
--counter;
--hist[oldv];
if(hist[oldv] == 1)
++counter;
}
arr[i] = newv; // set array
if(newv > 0 && newv <= N) { // increase histogram
if(hist[newv] == 1)
--counter;
++hist[newv];
if(hist[newv] == 1)
++counter;
}
}
// tests for permutation in O(1)
bool testPermutation() {
return counter == N;
}
You cannot tell if an array is a permutation without looking at each entry of the array, thus you need at least n steps in your algorithm.
A simple linear-time solution is to attempt to compute the inverse permutation (assuming 0-based indexing):
std::vector<int> inverse(n, -1);
for (int i = 0; i < n; ++i) {
if (array[i] < 0 || array[i] >= n || inverse[array[i]] != -1) {
break; // not a permutation!
}
inverse[array[i]] = i;
}

How can I find the minimum number of swaps in a consecutive unordered array (vector)?

I am trying to solve a problem:
You are given an unordered array consisting of consecutive integers [1, 2, 3, ..., n] without any duplicates nor specific order.You are allowed to swap any two elements. You need to find the minimum number of swaps required to sort the array in ascending order.
CONSTRAINTS:
the number of elements must be >= 1
the elements in the array must be <= to the size of the array
My code works when the numbers are not in the right position, but when the element is in the right position it enters an infinite loop, example array: [1 3 5 2 4 6 7] <- My code doesn't work because it gets stuck on 1.
My code:
#include <iostream>
#include <vector>
void swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
int minimumSwaps(std::vector<int> arr)
{
int numberOfSwaps = 0;
int lastElementIndex = (arr.size() - 1);
bool isSwapping = true;
while (isSwapping)
{
isSwapping = false;
for (int i = 0; i < arr.size(); i++)
{
if (lastElementIndex - (arr.size() - arr[i]) != 0)
{
isSwapping = true;
swap(arr[i], arr[lastElementIndex - (arr.size() - arr[i])]);
numberOfSwaps++;
}
else
{
std::cout << arr[i] << " is already in its perfect position." << std::endl;
}
}
}
return numberOfSwaps;
}
P.S: I've just used the else statement to check what was going wrong.
Replacing lastElementIndex with its value (arr.size() - 1)
in line
if (lastElementIndex - (arr.size() - arr[i]) != 0)
yields
if ((arr.size() - 1) - (arr.size() - arr[i]) != 0)
and this is equivalent to
if (arr[i] != 1)
That's obviously wrong. Replace the line with
if (arr[i] - 1 != i)

how to cout the longest permanent sequence (increasing or decreasing) in c++?

I have to make a program in C++ what can manage a sequence optionally with from 2 to 1000 element. At the end the program has to cout the longest increasing or decreasing sequence's numbers of element.
Examples:
6;1;2;3;2;4;1; output: 3; (because: 1;2;3 is the longest with 3 elements)
6;4;3;1;5;2;1; output: 4; (because: 6;4;3;1 is the longest with 4 elements)
I tired the following code and kind of working. The problem is that it cant give the longest one it gives the number of last sequence every time.
Unfortunately i cant find the bug or problem. Could anyone help please?
int counting = 1;
int counting_max = 0, counting_min = 0;
for (int i = 1; i < n; ++i) {
if(block[i] < block[i+1]) {
if(block[i]-block[i-1]>0) {
counting++;
if(counting>counting_max) {
counting_max = counting;
}}
else {
counting = 1;
}
}
if(block[i] > block[i+1]) {
if(block[i]-block[i-1]<0) {
counting++;
if(counting>counting_min) {
counting_min = counting;
}}
else {
counting = 1;
}
}
}
if(counting_max >= counting_min) {
cout<< counting_max;
}
else {
cout<< counting_min;
}
return 0;}
In my code I didn't share the first part because i guess it works properly.
The first is just a while and for function to call for the elements number and after the exact numbers in a block.
So in my code the block contains the numbers.
In the code you have posted your outer loop creates an out-of-bounds access of the block array, since you're accessing block[i+1] in the loop. That's likely the reason that your code is producing correct answers in one direction and not in the other.
Beyond that there are some other problems you might come across with this approach:
You probably don't need to keep track of two separate counters if in the end you take the largest. You could just keep track of the largest sequence regardless of if it increases or decreases.
Since you test the relationships between three elements in the array to see if the sequence is increasing/decreasing, you will have to add extra logic to handle when the list has fewer than three elements.
You need to be careful of when the same number repeats, as this probably does not count as increasing or decreasing.
Here's a revised version that covers these points:
int counting = std::min(n, 1);
int counting_max = counting;
for (int i = 0; i < n - 1; ++i) {
if (
block[i] < block[i + 1] &&
(counting < 2 || block[i] > block[i - 1])
) {
counting++;
} else if (
block[i] > block[i + 1] &&
(counting < 2 || block[i] < block[i - 1])
) {
counting++;
} else if (block[i] == block[i + 1]) {
counting = 1;
} else {
counting = 2;
}
if (counting > counting_max) {
counting_max = counting;
}
}
cout << counting_max << "\n";
Try this alternate code: counting_max is finding longest ascending sequence and counting_min is finding longest descending sequence(by decrementing its loop counter) and at the end, we compare them to find the ultimate longest(supposing we have n-1 elements, if not change it accordingly)
for (int i=1,j=n-2; i<n && j>=0; ++i,--j) {
if (block[i] - block[i - 1]>0) {
counting++;
if (counting>counting_max)
counting_max = counting;
}
else
counting = 1;
if (block[j] - block[j + 1]>0) {
counting_back++;
if (counting_back>counting_min)
counting_min = counting_back;
}
else
counting_back = 1;
}
if (counting_max >= counting_min)
cout << counting_max;
else
cout << counting_min;

C++ Bubble Sort Negative Numbers

I created a array bubble sort function for integers that works perfectly with positive integers but it crashes when negative integers are used. The initial display function works but then it just freezes. I have tried a signed int array to no avail.
I have looked all over but can't find anyone else with this exact problem.
int defaultArray[6] = { 12, -5, 21, -1, 15, 17 };
int numElements = 6;
int lastSwap;
int searchEnd = numElements - 1;
bool sorted = false;
while (!sorted)
{
for (int i = 0; i < searchEnd; ++i)
{
// If the number in position i is larger than the number in the
// position i + 1 then swap them
if (defaultArray[i] > defaultArray[i + 1]) {
int temp = defaultArray[i];
defaultArray[i] = defaultArray[i + 1];
defaultArray[i + 1] = temp;
lastSwap = i + 1;
}
}
// If the lastSwap is at position one we can conclude that the array is
// sorted so if lastSwap isn't 1 move searchEnd and continue
if (lastSwap != 1)
{
// Conclude that from lastSwap to the end of the array is sorted
// searchEnd begins one position to the left of lastSwap
searchEnd = lastSwap - 1;
}
else {
sorted = true;
}
You are trying to optimize your algorithm decreasing searchEnd, and I think that there is the problem. I recommend you to keep searchEnd the same. To determine if the array is sorted, set sorted to true and the start of the while loop and change it to false if a swap occurs. For example:
while (!sorted) {
sorted = true;
for (int i = 0; i < searchEnd; ++i) {
if (defaultArray[i] > defaultArray[i + 1]) {
// swap
sorted = false;
}
}
}

What is the fastest way to find longest 'consecutive numbers' streak in vector ?

I have a sorted std::vector<int> and I would like to find the longest 'streak of consecutive numbers' in this vector and then return both the length of it and the smallest number in the streak.
To visualize it for you :
suppose we have :
1 3 4 5 6 8 9
I would like it to return: maxStreakLength = 4 and streakBase = 3
There might be occasion where there will be 2 streaks and we have to choose which one is longer.
What is the best (fastest) way to do this ? I have tried to implement this but I have problems with coping with more than one streak in the vector. Should I use temporary vectors and then compare their lengths?
No you can do this in one pass through the vector and only storing the longest start point and length found so far. You also need much fewer than 'N' comparisons. *
hint: If you already have say a 4 long match ending at the 5th position (=6) and which position do you have to check next?
[*] left as exercise to the reader to work out what's the likely O( ) complexity ;-)
It would be interesting to see if the fact that the array is sorted can be exploited somehow to improve the algorithm. The first thing that comes to mind is this: if you know that all numbers in the input array are unique, then for a range of elements [i, j] in the array, you can immediately tell whether elements in that range are consecutive or not, without actually looking through the range. If this relation holds
array[j] - array[i] == j - i
then you can immediately say that elements in that range are consecutive. This criterion, obviously, uses the fact that the array is sorted and that the numbers don't repeat.
Now, we just need to develop an algorithm which will take advantage of that criterion. Here's one possible recursive approach:
Input of recursive step is the range of elements [i, j]. Initially it is [0, n-1] - the whole array.
Apply the above criterion to range [i, j]. If the range turns out to be consecutive, there's no need to subdivide it further. Send the range to output (see below for further details).
Otherwise (if the range is not consecutive), divide it into two equal parts [i, m] and [m+1, j].
Recursively invoke the algorithm on the lower part ([i, m]) and then on the upper part ([m+1, j]).
The above algorithm will perform binary partition of the array and recursive descent of the partition tree using the left-first approach. This means that this algorithm will find adjacent subranges with consecutive elements in left-to-right order. All you need to do is to join the adjacent subranges together. When you receive a subrange [i, j] that was "sent to output" at step 2, you have to concatenate it with previously received subranges, if they are indeed consecutive. Or you have to start a new range, if they are not consecutive. All the while you have keep track of the "longest consecutive range" found so far.
That's it.
The benefit of this algorithm is that it detects subranges of consecutive elements "early", without looking inside these subranges. Obviously, it's worst case performance (if ther are no consecutive subranges at all) is still O(n). In the best case, when the entire input array is consecutive, this algorithm will detect it instantly. (I'm still working on a meaningful O estimation for this algorithm.)
The usability of this algorithm is, again, undermined by the uniqueness requirement. I don't know whether it is something that is "given" in your case.
Anyway, here's a possible C++ implementation
typedef std::vector<int> vint;
typedef std::pair<vint::size_type, vint::size_type> range;
class longest_sequence
{
public:
const range& operator ()(const vint &v)
{
current = max = range(0, 0);
process_subrange(v, 0, v.size() - 1);
check_record();
return max;
}
private:
range current, max;
void process_subrange(const vint &v, vint::size_type i, vint::size_type j);
void check_record();
};
void longest_sequence::process_subrange(const vint &v,
vint::size_type i, vint::size_type j)
{
assert(i <= j && v[i] <= v[j]);
assert(i == 0 || i == current.second + 1);
if (v[j] - v[i] == j - i)
{ // Consecutive subrange found
assert(v[current.second] <= v[i]);
if (i == 0 || v[i] == v[current.second] + 1)
// Append to the current range
current.second = j;
else
{ // Range finished
// Check against the record
check_record();
// Start a new range
current = range(i, j);
}
}
else
{ // Subdivision and recursive calls
assert(i < j);
vint::size_type m = (i + j) / 2;
process_subrange(v, i, m);
process_subrange(v, m + 1, j);
}
}
void longest_sequence::check_record()
{
assert(current.second >= current.first);
if (current.second - current.first > max.second - max.first)
// We have a new record
max = current;
}
int main()
{
int a[] = { 1, 3, 4, 5, 6, 8, 9 };
std::vector<int> v(a, a + sizeof a / sizeof *a);
range r = longest_sequence()(v);
return 0;
}
I believe that this should do it?
size_t beginStreak = 0;
size_t streakLen = 1;
size_t longest = 0;
size_t longestStart = 0;
for (size_t i=1; i < len.size(); i++) {
if (vec[i] == vec[i-1] + 1) {
streakLen++;
}
else {
if (streakLen > longest) {
longest = streakLen;
longestStart = beginStreak;
}
beginStreak = i;
streakLen = 1;
}
}
if (streakLen > longest) {
longest = streakLen;
longestStart = beginStreak;
}
You can't solve this problem in less than O(N) time. Imagine your list is the first N-1 even numbers, plus a single odd number (chosen from among the first N-1 odd numbers). Then there is a single streak of length 3 somewhere in the list, but worst case you need to scan the entire list to find it. Even on average you'll need to examine at least half of the list to find it.
Similar to Rodrigo's solutions but solving your example as well:
#include <vector>
#include <cstdio>
#define len(x) sizeof(x) / sizeof(x[0])
using namespace std;
int nums[] = {1,3,4,5,6,8,9};
int streakBase = nums[0];
int maxStreakLength = 1;
void updateStreak(int currentStreakLength, int currentStreakBase) {
if (currentStreakLength > maxStreakLength) {
maxStreakLength = currentStreakLength;
streakBase = currentStreakBase;
}
}
int main(void) {
vector<int> v;
for(size_t i=0; i < len(nums); ++i)
v.push_back(nums[i]);
int lastBase = v[0], currentStreakBase = v[0], currentStreakLength = 1;
for(size_t i=1; i < v.size(); ++i) {
if (v[i] == lastBase + 1) {
currentStreakLength++;
lastBase = v[i];
} else {
updateStreak(currentStreakLength, currentStreakBase);
currentStreakBase = v[i];
lastBase = v[i];
currentStreakLength = 1;
}
}
updateStreak(currentStreakLength, currentStreakBase);
printf("maxStreakLength = %d and streakBase = %d\n", maxStreakLength, streakBase);
return 0;
}