Generate all permutation of an array without duplicate result - c++

This is a leetcode question permutation2.
Given a array num (element is not unique, such as 1,1,2), return all permutations without duplicate result. For example, num = {1,1,2} should have permutations of {1,1,2},{1,2,1},{2,1,1}.
I came up with a solution as follow. Basically, I recursively generate permutations. Assuming [0, begin-1] is fixed, then recursively generate permutation of [begin, lastElement].
vector<vector<int> > permuteUnique(vector<int> &num) {
vector<vector<int> > res;
if(num.empty())
return res;
helper(num, 0, res);
return res;
}
//0...begin-1 is already permutated
void helper(vector<int> &num, int begin, vector<vector<int> > &res)
{
if(begin == num.size())
{
res.push_back(num);//This is a permutation
return;
}
for(int i = begin; i<num.size(); ++i)
{
if(i!=begin&&num[i]==num[begin])//if equal, then [begin+1,lastElement] would have same permutation, so skip
continue;
swap(num[i], num[begin]);
helper(num, begin+1, res);
swap(num[i], num[begin]);
}
}
I was wondering if this is the right solution since leetcode oj gave me Output Limit while my xCode IDE can return the right answer for several cases.
My main concern is does this if(i!=begin&&num[i]==num[begin])continue; can really skip the duplicate result? If not, what is the counter example?
Thanks for sharing your thoughts!

With STL, the code may be:
std::vector<std::vector<int> > permuteUnique(std::vector<int> num) {
std::sort(num.begin(), num.end());
std::vector<std::vector<int> > res;
if(num.empty()) {
return res;
}
do {
res.push_back(num);
} while (std::next_permutation(num.begin(), num.end()));
return res;
}
Live demo
Your test is not sufficient to skip duplicates. For entry {2, 1, 1}, you got:
{2, 1, 1}
{1, 2, 1}
{1, 1, 2}
{1, 1, 2}
{1, 2, 1}
So 2 duplicates.

Related

I am getting this error while sorting 0,1 and 2 in array - Runtime Error Time Limit Exceeded Your program took more time than expected

class Solution
{
public:
void sort012(int a[], int n)
{
// code here
int low = 0;
int high = n-1;
int mid = 0;
while(mid<high)
{
int high = n-1;
if(a[mid]==0 && mid<=high)
{ swap(a[mid++],a[low++]);
}
else if(a[mid]==2 && mid<=high)
{ swap(a[mid],a[high--]);
}
else if(a[mid]==1 && mid<=high)
{
mid++;
}
}
}
};
Problem number one is you are redefining the int high = n - 1 inside of the while loop, at each iteration it's reset to this value, so high-- has no effect, and you're getting inside an infinite loop.
Problem number two is that potentially if you pass an array a which has a single value that is not a 0, 1 or 2, you are 100% getting into an infinite loop as well.
Check out this compiler explorer link for an interactive demo: https://godbolt.org/z/EbKPqrxz4
For what it's worth, you program looks like bad C instead of being C++. Non exhaustive list of issues:
The sort012 is an instance method on a class while it doesn't use the instance state. It's probably better as a free function, or at worse a static method on that class.
You're using C arrays.
As a result, you're also not using the algorithms provided by the STL.
I'm assuming this is a kind of coding exercise, but anyways, for the sake of completeness you could achieve the same thing (and more, it'd work with several containers, and regardless of your values/types) with fewer lines of code with this (Compiler Explorer):
#include <fmt/format.h>
#include <algorithm>
#include <array>
int main() {
std::array<int, 10> a{1, 2, 0, 1, 2, 1, 2, 1, 0, 2};
// Could also be a vector: `std::vector<int> a{1, 2, 0, 1, 2, 1, 2, 1, 0, 2};`
std::sort(a.begin(), a.end());
fmt::print("sorted a=");
for (auto x: a) {
fmt::print("{}, ", x);
}
}

Clustering example in C++

I have an increasing input vector like this {0, 1, 3, 5, 6, 7, 9} and want to cluster the inputs like this {{0, 1}, {3}, {5, 6, 7}, {9}} i.e cluster only the integers that are neighbors. The data structure std::vector<std::vector<int>> solution(const std::vector<int>& input)
I usually advocate for not giving away solutions, but it looks like you're getting bogged down with indices and temporary vectors. Instead, standard iterators and algorithms make this task a breeze:
std::vector<std::vector<int>> solution(std::vector<int> const &input) {
std::vector<std::vector<int>> clusters;
// Special-casing to avoid returning {{}} in case of an empty input
if(input.empty())
return clusters;
// Loop-and-a-half, no condition here
for(auto it = begin(input);;) {
// Find the last element of the current cluster
auto const last = std::adjacent_find(
it, end(input),
[](int a, int b) { return b - a > 1; }
);
if(last == end(input)) {
// We reached the end: register the last cluster and return
clusters.emplace_back(it, last);
return clusters;
}
// One past the end of the current cluster
auto const gap = next(last);
// Register the cluster
clusters.emplace_back(it, gap);
// One past the end of a cluster is the beginning of the next one
it = gap;
}
}
See it live on Coliru (lame output formatting free of charge)

Finding vectors in C++

I have two vectors of vector<unsigned> namely: vector<vector<unsigned> > sbp, vector<vector<unsigned> > sp. I want to print all those vectors in sbp which are also in sp. Both vectors sbp and sp are stored (i) first by size; (ii) and when the size are equal, then the vectors are sorted lexicographically. I wrote the following code for doing the same. The code appears to be giving segmentation fault. I debugged the code (by printing out values), but I am not able to find the source of the error.
Can someone please help me find what could be the source of segmentation fault. Also if there is some algorithm which is faster than this, then that will be really great
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
vector<vector<unsigned> > sbp;
vector<vector<unsigned> > sp;
vector<vector<unsigned> >::iterator itSP=sp.begin();
for(vector<vector<unsigned> >::iterator itSbp=sbp.begin(),lSbp=sbp.end();itSbp!=lSbp;)
{
if(std::lexicographical_compare(((*itSbp)).begin(), ((*itSbp)).end(), (*itSP).begin(), (*itSP).end()))
{
itSbp++;
}else{
if((*itSbp)==(*itSP))
{
// cout<<(*itSbp)<<"\n";
itSbp++;
}else{
itSP++;
}
}
}
}
I am using C++11(gcc 4.8)
I want to print all those vectors in sbp which are also in sp.
Whenever there is a situation where you want to collate the common values that are in two containers, the algorithm that should spring to mind right away is std::set_intersection.
The caveat is that std::set_intersection requires that the containers contain sorted values (or a functor provided that describes the sort order). However, if you can meet that criteria, then the solution is trivial.
Here is an example:
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
// test data
vector<vector<unsigned> > sbp = { { 1, 2, 3, 4, 6, 7 }, { 1, 2, 3, 6, 7 }, { 2, 3, 4, 6, 7 }};
vector<vector<unsigned> > sp = { { 1, 2, 3, 4, 6, 7 }, { 1, 2, 3, 4, 6, 7, 8 }, { 2, 3, 4, 6, 7 }};
// resulting vector
vector<vector<unsigned> > result;
// get the intersection of the two values
set_intersection(sbp.begin(), sbp.end(), sp.begin(), sp.end(), back_inserter(result));
// output the results
for_each(result.begin(), result.end(), [](const std::vector<unsigned>& v)
{copy(v.begin(), v.end(), ostream_iterator<unsigned>(cout, " ")); cout << "\n";});
}
Live Example
If the number of items are large, and there is a good possibility that the data contains duplicates, then a std::set can be used to store the data.
// resulting vector
std::set<vector<unsigned>> result;
// get the intersection of the two values
set_intersection(sbp.begin(), sbp.end(), sp.begin(), sp.end(), std::inserter(result, result.begin()));

BFS paths C++ implementation returning return an extra value

I'm trying to implement a function using Breadth First Search to find the paths given a start and end nodes. I'm new to c++, I implemented the same in python already and it works.
With the following graph, it should give the paths {{1, 3, 6}, {1, 2, 5, 6}}:
map<int, vector<int> > aGraph = {
{1, {2, 3}},
{2, {1, 4, 5}},
{3, {1, 6}},
{4, {2}},
{5, {2, 6}},
{6, {3, 5}}
};
I created a function called BFSPaths to solve the problem, however I keep on getting an extra digit in the answer {{1, 2, 3, 6}, {1, 2, 4, 5, 6}}. I haven't been able to figure out why the 2 and the 4 are being added to the answer. This is how the functions looks like:
vector<vector<int>> BFSPaths(map<int, vector<int>> &graph, int head, int tail)
{
vector<vector<int>> out;
vector<int> init {head};
vector<tuple<int, vector<int>>> queue = { make_tuple(head, init) };
while (queue.size() > 0)
{
int vertex = get<0>(queue.at(0));
vector<int> path = get<1>(queue.at(0));
queue.erase(queue.begin());
vector<int> difference;
sort(graph.at(vertex).begin(), graph.at(vertex).end());
sort(path.begin(), path.end());
set_difference(
graph.at(vertex).begin(), graph.at(vertex).end(),
path.begin(), path.end(),
back_inserter( difference )
);
for (int v : difference)
{
if (v == tail)
{
path.push_back(v);
out.push_back(path);
}
else
{
path.push_back(v);
tuple<int, vector<int>> temp (v, path);
queue.push_back(temp);
}
}
}
return out;
}
This is how I'm calling my function (to print to the shell):
void testBFSPaths(map<int, vector<int>> &graph, int head, int tail)
{
vector<vector<int>> paths = BFSPaths(graph, head, tail);
for (int i=0; i<paths.size(); i++)
{
print(paths.at(i));
}
}
int main ()
{
// graph definition goes here ....
testBFSPaths(aGraph, 1, 6);
}
I would appreciate if someone can give me a push in the right direction.
As far as I understand your calculating the set difference between reachable vertices and the path to the current vertex here:
set_difference(
graph.at(vertex).begin(), graph.at(vertex).end(),
path.begin(), path.end(),
back_inserter( difference )
);
But it does not make any sense in terms of BFS. As you can see further, you are adding vertices from this difference to your answer no matter if they lies on path from head to tail or not.
You should look to another approach in this case and change your algorithm a little bit.
Steps that I would recommend:
Add the head vertex as you do, but without a path.
Extract queue's head and add all adjacent vertices to queue with a link to their predecessor.
Repeat until queue is not empty or tail is reached.
Get the path from head to tail by following links to predecessors.
Btw, I would recommend you not to use queue.erase(...) method when you want to delete a head of queue (use queue.pop() instead). And also, you can change map.at(key) method to simple map[key].
The last thing -- it looks for me not very clear why do you store adjacent vertices in vector<int> if you have to sort them often. Use smth like set<int> instead so you will not have to worry about it.
The problems was that the path was being updated path.insert(path.end(), v). I need to use a temporary path so that the original path was not needlessly changed by visited nodes during the iteration.
I also used sets (not much of a difference, it only removes the sorting step).
The function after fixed looks like this:
vector<set<int>> BFSPaths(map<int, set<int>> &graph, int head, int tail)
{
vector<set<int>> out;
set<int> init {head};
queue<tuple<int, set<int>>> aQueue;
aQueue.push( make_tuple(head, init) );
while (aQueue.size() > 0)
{
int vertex = get<0>(aQueue.front());
set<int> path = get<1>(aQueue.front());
aQueue.pop();
vector<int> difference;
set_difference(
graph[vertex].begin(), graph[vertex].end(),
path.begin(), path.end(),
back_inserter( difference )
);
for (int v : difference)
{
set<int> tempPath;
tempPath.insert(path.begin(), path.end());
tempPath.insert(tempPath.end(), v);
if (v == tail)
{
out.push_back(tempPath);
}
else
{
tuple<int, set<int>> temp (v, tempPath);
aQueue.push(temp);
}
}
}
return out;
}
The tempPath is now what's passed to the queue or added to the out vector.

Good C++ solutions to the "Bring all the zeros to the back of the array" interview challenge

I had an interview for a Jr. development job and he asked me to write a procedure that takes an array of ints and shoves the zeroes to the back. Here are the constraints (which he didn't tell me at the beginning .... As often happens in programming interviews, I learned the constraints of the problem while I solved it lol):
Have to do it in-place; no creating temporary arrays, new arrays, etc.
Don't have to preserve the order of the nonzero numbers (I wish he would've told me this at the beginning)
Setup:
int arr[] = {0, -2, 4, 0, 19, 69};
/* Transform arr to {-2, 4, 19, 69, 0, 0} or {69, 4, -2, 19, 0, 0}
or anything that pushes all the nonzeros to the back and keeps
all the nonzeros in front */
My answer:
bool f (int a, int b) {return a == 0;}
std::sort(arr, arr+sizeof(arr)/sizeof(int), f);
What are some other good answers?
Maybe the interviewer was looking for this answer:
#include <algorithm>
//...
std::partition(std::begin(arr), std::end(arr), [](int n) { return n != 0; });
If the order needs to be preserved, then std::stable_partition should be used:
#include <algorithm>
//...
std::stable_partition(std::begin(arr), std::end(arr), [](int n) { return n != 0; });
For pre C++11:
#include <functional>
#include <algorithm>
//...
std::partition(arr, arr + sizeof(arr)/sizeof(int),
std::bind1st(std::not_equal_to<int>(), 0));
Live Example
Basically, if the situation is that you need to move items that satisfy a condition to "one side" of a container, then the partition algorithm functions should be high up on the list of solutions to choose (if not the solution to use).
An approach that sorts is O(N*Log2N). There is a linear solution that goes like this:
Set up two pointers - readPtr and writePtr, initially pointing to the beginning of the array
Make a loop that walks readPtr up the array to the end. If *readPtr is not zero, copy to *writePtr, and advance both pointers; otherwise, advance only readPtr.
Once readPtr is at the end of the array, walk writePtr to the end of the array, while writing zeros to the remaining elements.
This is O(n) so it may be what he's looking for:
auto arrBegin = begin(arr);
const auto arrEnd = end(arr);
for(int i = 0; arrBegin < arrEnd - i; ++arrBegin){
if(*arrBegin == 0){
i++;
*arrBegin = *(arrEnd - i);
}
}
std::fill(arrBegin, arrEnd, 0);