Check if vector<int> contains duplicate absolute values - c++11

Attempting to determine if a vector contains a duplicate. This applies to the absolute value of the elements in the vector. I have tested my implementation with a few cases and have gotten inconsistent results.
bool has_duplicate(vector<int> v) {
vector<int>::iterator it;
for (it = v.begin(); it != v.end(); ++it) {
if (v[*it] < 0)
v[*it *= -1;
if (count(v.begin(), v.end(), v[*it]) > 1)
return true;
}
return false;
}
vector<int> v1 {1, -1}; // true
vector<int> v3 {3, 4, 5, -3}; // true
vector<int> v2 {2, -2}; // false
vector<int> v4 {3, 4, -3}; // false
vector<int> v5 {-1, 1}; // false
Any insight on the erroneous implementation is appreciated

An iterator is like a pointer, not like an index, so you're definitely misusing them in your code. It didn't compile for me. It looks like you're trying to search every element in the vector against every other element, which is inefficient, with a time complexity closer to O(N^2). Since your function only wants to see whether a duplicate exists, you can stop as soon as you find one. By using a set to keep track of what you've found so far, you have a time complexity closer to O(N*log(N)).
bool has_duplicate(vector<int> v)
{
set<int> s;
for (auto i = v.begin(); i != v.end(); ++i) {
int ai = abs(*i);
if (s.count(ai)) return true;
s.insert(ai);
}
return false;
}

bool hasDuplicate(std::vector<int> v)
{
std::transform(v.begin(), v.end(), v.begin(), ::abs);
std::sort(v.begin(), v.end());
return std::adjacent_find(v.begin(), v.end()) != v.end();
}

Related

how the insertion in 2d vector ans working in the following code?

In ans vector, man[1] might have 0 for 2 elements in the vector eg:[7,0],[8,0] if once [8,0] is encountered then if [7,0] is encountered next won't this over write the value of [8,0] as [7,0]?I have a difficulty in understanding how the insertion is happening.
People = [[7,0], [4,4], [7,2], [5,0], [6,1], [5,4], [8,0]]
Sorted People according to comp function : [[8,0], [7,0], [7,2], [6,1], [5,0], [5,4], [4,4]]]
class Solution {
public:
static bool comp(vector<int>& a, vector<int>& b){ //Comparator function for the logic of sort
if(a[0] == b[0]) return a[1] < b[1];
return a[0] > b[0];
}
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
sort(people.begin(), people.end(), comp); //Sorting the array according to comp function.
vector<vector<int>> ans; //to store the final array to be returned
for(auto man : people){
ans.insert(ans.begin()+man[1], man); //Inserting the element at desired position.
}
return ans;
}
};

Sliding Puzzle using BFS

I am working on Leetcode problem https://leetcode.com/problems/sliding-puzzle/
class Solution {
public:
int slidingPuzzle(vector<vector<int>>& board) {
int res = 0;
set<vector<vector<int>>> visited;
queue<pair<vector<vector<int>>, vector<int>>> q;
vector<vector<int>> correct{{1, 2, 3}, {4, 5, 0}};
vector<vector<int>> dirs{{0, -1}, {-1, 0}, {0, 1}, {1, 0}};
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 3; ++j) {
if (board[i][j] == 0) q.push({board, {i, j}});
}
}
while (!q.empty()) {
for (int i = q.size() - 1; i >= 0; --i) {
vector<vector<int>> t = q.front().first;
auto zero = q.front().second; q.pop();
if (t == correct) return res;
visited.insert(t);
for (auto dir : dirs)
{
int x = zero[0] + dir[0], y = zero[1] + dir[1];
if (x < 0 || x >= 2 || y < 0 || y >= 3) continue;
/* option1
vector<vector<int>> cand = t;
swap(cand[zero[0]][zero[1]], cand[x][y]);
if (visited.count(cand)) continue;
q.push({cand, {x, y}});
*/
/* option2
swap(t[zero[0]][zero[1]], t[x][y]);
if (visited.count(t)) continue;
q.push({t, {x, y}});
swap(t[zero[0]][zero[1]], t[x][y]);
*/
}
}
++res;
}
return -1;
}
};
if I keep option1 remove option2 it works,
however when I keep option2 remove option1 it doesn't work!
But these two code block should work the same. I have been trying to figure it out for a couple of hours. So frustrated and no clue
The Bug is in here if (visited.count(t)) continue;
basically, when visited.count(t) is true you will not undo the swap.
The purpose of option1 and option2 is to generate a new valid board state. In your option1, you follow the following states:
copy the current board state into a new temporary board instance (e.g., cand vector)
move the empty tile towards dir
skip the following step if you already visited the new state before
insert the new state into the queue
It works perfectly fine, except the memory utilization. That's why you probably tried doing the moves in-place (e.g., in your option2). The steps of your option2 is like this:
move the empty tile towards dir
skip the following steps if you already visited the new state before <-- this is where you made the mistake
insert the new state into the queue
move back the empty tile to it's original location
You made the mistake in your 2nd step, as you do not undo the change if a newly generated state is already visited. Please check the following code, it will solve your problem:
// option2
swap(t[zero[0]][zero[1]], t[x][y]);
if (!visited.count(t)) q.push({t, {x, y}});
swap(t[zero[0]][zero[1]], t[x][y]);

SubsetSum using recursion and backtracking

I have written an algorithm to return whether a subset of a group of numbers will sum to a given target using backtracking and recursion (returns true/false)
Ex: {5, 2, 3, 6} with Target = 8 ==> True ||
{5, 2, 3, 6} with Target = 20 ==> False
I want to modify my algorithm so that it includes all 5's that maybe present in the set. I am having a hard time how to figure this out using backtracking and recursion. Any advice is appreciated
Ex: {5, 2, 3, 6} with Target 8 ==>True ||
{6, 2, 3, 5, 5} with Target 8 ==> False
I have written an algorithm that recursively includes a number and checks the sum and then omits the number from the sum but I don't know how to modify my algorithm to only pick a certain numbers and include them in the sum
public static void main(String argv[]) {
int[] ints = { 10, 1, 3, 2 };
int target = 5;
int start = 0;
System.out.println(groupSum(ints, target, 0, start));
}
public static boolean groupSum(int[] arr, int target, int sum, int start) {
if (sum > target) {
return false;
}
if (sum == target) {
return true;
}
if (start >= arr.length) {
return false;
}
//choose
sum = sum + arr[start];
//explore
if (groupSum(arr, target, sum, start + 1))
return true;
//un-choose
sum = sum - arr[start];
return groupSum(arr, target, sum, start + 1);
}
Force it to only look at including 5 if it sees it, and only check = sum at the end. Like this:
public static void main(String argv[]) {
int[] ints = { 10, 1, 3, 2 };
int target = 5;
int start = 0;
System.out.println(groupSum(ints, target, 0, start));
}
public static boolean groupSum(int[] arr, int target, int sum, int start) {
if (sum > target) {
return false;
}
// NOTE: sum == target inside of end of array check so all 5s are found.
if (start >= arr.length) {
return sum == target;
}
//choose
sum = sum + arr[start];
//explore
if (groupSum(arr, target, sum, start + 1))
return true;
//un-choose
// NOTE: can't unchoose 5
if (5 == arr[start]) {
return false;
}
sum = sum - arr[start];
return groupSum(arr, target, sum, start + 1);
}
Update: Here is advice on how to solve problems like this.
Very clearly state what you want the function to do.
Very clearly state what the base case or cases are where you know the answer.
In the complex case, figure out how to reduce it to one or more simpler problems.
As long as you've done that, your recursive code should work. And if you're in doubt about how to modify, start over from scratch, only copying code from before where you've noticed that it can be left alone.
So for the first step, the statement is, We want groupSum to take an array arr of positive integers, a target target, a partial sum sum and an int start and to return whether it is possible to get the rest of the array to sum to target when you take a subset that has to include all 5s.
For the second step, base cases are:
We've already exceeded target, then it is false.
We've reached the end of the array and are at target, then it is true.
We've reached the end of the array and are blow target, then it is false. (I combined this with the last in the code by returning a comparison.)
For the third step, the reductions are as follows.
If we can add the current value and make it, the answer is true.
If the current value is not 5, we don't add it, and can make it, the answer is true.
Otherwise it is false.
I was trying to write the code in the way that looked most like what you already had. But to write it exactly according to this logic it would be like this:
public static boolean groupSumWithAll5s(int[] arr, int target, int sum, int start) {
// Base cases
if (sum > target) {
return false;
}
else if ((start >= arr.length) && (sum == target)) {
return true;
}
else if (start >= arr.length) {
return false;
}
// Recursive cases.
if (groupSumWithAll5s(arr, target, sum + arr[start], start + 1)) {
return true;
}
else if ((arr[start] != 5) && groupSumWithAll5s(arr, target, sum, start + 1)) {
return true;
}
else {
return false;
}
}

iterate through a set goes to infinite loop

i used exactly the same code in both of my files.
and one is work properly while the other one (this one) goes to endless loop.
int arr[5] = {3, 1, 3, 5, 6};
int main() {
int T = 1;
set<int> s;
for (int tc = 0; tc < T; tc++) {
s.emplace(0);
for (auto x : arr) {
auto end = s.end();
for (auto it = s.begin(); it != end; it++) {
// here's where goes to infinite loop
// and i couldn't figure out why..
s.emplace(*it+x);
}
}
}
return 0;
}
below one is well working one
using namespace std;
int main() {
int arr[5] = {3,1,3,5,6}, sum=20;
set<int> s;
s.emplace(sum);
for (auto x : arr) {
auto end = s.end();
for (auto it = s.begin(); it != end; it++) {
s.emplace(*it-x);
}
}
return 0;
}
expected results are s = {1, 4, 7, 8, ...}
all the sum of all the subset of arr.
but not working properly.. i don't know why..
The issue is that you're inserting elements into the set while iterating over it (with the ranged-for loop). The ranged-for loop semantics do not involve remembering the state of the range before the loop started; it's just like writing:
for(auto it = std::begin(container); it < std::end(container); it++)
Now, std::set is an ordered container. So when you insert/emplace elements smaller than the one your iterator points at, you won't see them later on in the iteration; but if you insert larger elements, you will see them. So you end up iterating only over elements you've inserted, infinitely.
What you should probably be doing is not emplace new elements into s during the iteration, but rather place them in some other container, then finally dump all of that new containers' contents into the set (e.g. with an std::inserter to the set and an std::copy).
(Also, in general, all of your code seems kind of suspect, i.e. I doubt you really want to do any of this stuff in the first place.)

find permutation of an array with duplicates. Why pass by value in recursion (C++ implementation)

There are different ways to find all permutation of an integer array with duplicates. Here I only talk about the recursive method without using an additional "visited[]" array.
There correct way to do it is:
void helper(vector<vector<int>>& ans, vector<int> nums, int pos) {
if(pos == nums.size()-1) {
ans.push_back(nums);
return;
}
for(int i = pos; i < nums.size(); i++) {
if(i == pos || nums[i] != nums[pos]) {
swap(nums[i], nums[pos]);
helper(ans, nums, pos+1);
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> ans;
sort(nums.begin(), nums.end());
helper(ans, nums, 0);
return ans;
}
It is not so clear to me why it passes nums[] as a copy into the recursive function. So I looked around and on geeks for geeks , it says that "The idea is to fix the first character at first index and recursively call for other subsequent indexes". I was thinking that I can fix the first character then recursively call for the other subsequent indexes by passing nums[] as reference and "swap back" when recursion is done (as below). But unfortunately it did not work.
void helper(vector<vector<int>>& ans, vector<int>& nums, int pos) {
if(pos == nums.size()-1) {
ans.push_back(nums);
return;
}
for(int i = pos; i < nums.size(); i++) {
if(i == pos || nums[i] != nums[i-1]) {
swap(nums[i], nums[pos]);
helper(ans, nums, pos+1);
swap(nums[i], nums[pos]);
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> ans;
sort(nums.begin(), nums.end());
helper(ans, nums, 0);
return ans;
}
I am wondering what is wrong when passing nums[] as reference into recursion? Why passing nums[] by copy into recursion is correct?
I think I found the reason. Passing by value and passing by reference give two totally different algorithms. To understand that. Let's first note two important observations:
The first thing we did is to sort the array, why? because we want that all the permutations are visited in the "next permutation" order, i.e. 123, 132, 213, 231, 312, 321. So that there will be no duplicates.
The subproblem in the next recursion also maintained the sorted property. Let's use an example to illustrate this.
Input nums = [1,2,2,3] passing by value to recursion, with pos = 0,
i = 0: subproblem is [2,2,3],
i = 1: subproblem is [1,2,3],
i = 2: skipped,
i = 3 subproblem is [1,2,2].
All the subproblems in this level of recursion are all SORTED.
But if [1,2,2,3] is passed by reference, the subproblems are NOT sorted, so you can not reply on "next permutation" method to give you non-duplicated permutations.
If you are still confused, please take some time to read through this discussion:
https://discuss.leetcode.com/topic/8831/a-simple-c-solution-in-only-20-lines/28?page=2

Resources