How do I account for duplicate values when solving the the two sum problem using a hash table? - algorithm

Say I have the classic Two Sum Problem but with a twist
If I am given a list of integers and target
I need to print all the pairs of values that add up to the sum
Without repeating symmetrical values
Without reusing a value
I am trying to avoid the brute force approach for obvious reasons, but if I implement a hash-map with each value as the key and the element being the frequency of that value in the original array. How do I get the algorithm to only print each value pair once?
function findPairs(arr, target){
let hashMap = {};
let results = [];
for(let i = 0; i < arr.length; i++){
if(hashMap.hasOwnProperty(arr[i])){
hashMap[arr[i]]++;
}else{
hashMap[arr[i]] = 1;
}
}
for(let i = 0; i < arr.length; i++){
let diff = target - arr[i];
if(hashMap.hasOwnProperty(diff) && hashMap[diff] > 0){
results.push([arr[i], diff]);
hashMap[diff]--;
}
}
console.log(results);
}
findPairs([1, 3, -1, 11, 7], 10);
findPairs([5, 5, 5, 5, 5], 10);
findPairs([1, 3, -1, 11, 7], 10)
(3, 7)
(-1, 11)
findPairs([5, 5, 5], 10)
(5, 5)
findPairs([5, 5, 5, 5], 10)
(5, 5)
(5, 5)
findPairs([5, 5, 5, 5, 5], 10)
(5, 5)
(5, 5)
findPairs([5, 5, 5, 5, 5, 5 ], 10)
(5, 5)
(5, 5)
(5, 5)

This is the summary of the question as far as I understood:
Your array can have duplicate elements eg:- [1, 2, 3, 2, 4]
You want to print duplicate [4, 1, 2, 3, 2, 4] as (2, 4), (2, 4)
vector<pair<int, int> > findPairs(vector<int> arr, int target){
int size = arr.size();
map<int, int> hashMap;
for(int i = 0; i < size; i++){
// C++ map assigns 0 as default if the key is not present, C++ map uses Red Black Tree
if(hashMap[arr[i]] == 0)
hashMap[arr[i]] = 1;
else
hashMap[arr[i]]++;
}
/** Use to store result in (int, int) form
* Vector is a Dynamic array
*/
vector<pair<int, int> > results;
for(int i = 0; i < size; i++){
int diff = target - arr[i];
hashMap[arr[i]]--;
if(hashMap[diff] >= 1)
results.push_back(make_pair(arr[i], diff));
hashMap[diff]--;
}
return results;
}
This code is based on the examples you have provided in the question.

Related

All variations of a number

Im trying to find all the possible variations of a number in the form of:
'1_2_3_4' where _ is a number between 0 to 9.
I was wondering what is the best approach to this problem.
This seems like the simplest method:
static void printPerms()
{
int n = 1020304;
for (int i = 0; i <= 9; i++, n += 90000)
for (int j = 0; j <= 9; j++, n += 900)
for (int k = 0; k <= 9; k++, n += 10)
System.out.println(n);
}
Or even this, which has a lovely symmetry:
static void printPerms()
{
int n = 1020304;
for (int ni = n + 900000; n <= ni; n += 90000)
for (int nj = n + 9000; n <= nj; n += 900)
for (int nk = n + 90; n <= nk; n += 10)
System.out.println(n);
}
import java.util.*;
public class Solution {
public static void main(String[] args){
int[] fillable = {1,-1,2,-1,3,-1,4};
for(int i=0;i<=9;++i){
for(int j=0;j<=9;++j){
for(int k=0;k<=9;++k){
fillable[1] = i;
fillable[3] = j;
fillable[5] = k;
System.out.println(Arrays.toString(fillable));
}
}
}
}
}
OUTPUT:
[1, 0, 2, 0, 3, 0, 4]
[1, 0, 2, 0, 3, 1, 4]
[1, 0, 2, 0, 3, 2, 4]
[1, 0, 2, 0, 3, 3, 4]
[1, 0, 2, 0, 3, 4, 4]
[1, 0, 2, 0, 3, 5, 4]
[1, 0, 2, 0, 3, 6, 4]
.
.
.
.
Time Complexity: O(10^n) where n is no. of places to fill in. If 3 empty places if fixed, then it is O(1).
Space Complexity: O(1)
Note: There is no better way to do this. You have to go through each and every combination.
Python style, assuming ASCII code representation:
n= "1020304"
while True:
n[5]+= 1
if n[5] == ':':
n[5]= '0'
n[3]+= 1
if n[3] == ':':
n[3]= '0'
n[1]+= 1
if n[1] == ':'=
break

Algorithms: distribute elements far away from each other

I have an array of sorted integers. Given an integer N i need to place N largest elements further away from each other so that they have maximum space between each other. The remaining elements should be placed between these big items. For example, array of 10 with N=3 would result in [0, 5, 8, 2, 6, 9, 3, 7, 10, 4].
public static void main(String[] args) {
int[] start = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
int[] end = new int[10];
int N = 4;
int step = Math.round(start.length / N );
int y = 0;
int count = 0;
for (int i = 0; i < step; i++) {
for (int j = i; j<start.length; j = j + step) {
//System.out.println(j + " " + i);
if (count < start.length && start[count] != 0) {
end[j] = start[count];
count++;
}
}
}
System.out.println(end.toString());
}
You have an array of K elements. You have N max numbers you need to distribute. Then:
Step := K/N (removing the remainder)
Take any number from N maximum and insert it at Step/2 position.
Take other maximum numbers and insert it after the previous inserted maximum number at Step distance.
Giving [1,2,3,4,5,6,7,8,9,10]. So K = 10, N = 3. Then Step = 3. So the first maximum is placed at 3/2 position
[1,10,2,3,4,5,6,7,8,9]
Then other 2 are put at 3 distance from each other:
[1,10,2,3,9,4,5,8,6,7]
The code:
std::vector<int> Distribute(std::vector<int> aSource, int aNumber)
{
auto step = aSource.size() / aNumber; // Note integer dividing.
for (int i = 0; i < aNumber; ++i)
{
auto place = aSource.end() - i * step - step / 2;
aSource.insert(place, aSource.front());
aSource.erase(aSource.begin());
}
return aSource;
}
int main()
{
std::vector<int> vec{10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
auto res = Distribute(vec, 4);
for (auto e : res)
{
std::cout << e << ", ";
}
std::cout << std::endl;
}
Output:
6, 5, 4, 7, 3, 2, 1, 0, 8, -1, -2, -3, -4, 9, -5, -6, -7, -8, 10, -9, -10,

Insertion sort in the opposite direction. Sorted portion to the right and unsorted to the left

I am trying to inverse the sorted portion and unsorted portion in the insertion sort logic described in CLR. The output is completely erroneous. Can somebody point the mistake or logic error in my code.
#include<stdio.h>
#include<stdlib.h>
int main()
{ int a[] = {67,7,3,2,1,9,45,5};
int k;
int n = sizeof(a)/sizeof(a[0]);
insert(a,n);
for(k = 0;k < n; k++)
printf("%d %d\n",k,a[k]);
return 0;
}
void insert(int *a,int n)
{
int i,j,val;
for(i=n-2;i>=0;i--){
val=a[i];
for(j=i+1;j<n && a[j]<val;j++){
a[j-1]=a[j];
}
a[j--]=val;
}
You should insert the last element at a[j - 1]. You can achieve this with a decrement, but in that case you must use a prefix decrement, which changes the value before referencing it: a[--j] = val;.
Here's a corrected version:
void insertion_sort_backwards(int *a, int n)
{
int i = n - 1;
while (i--) {
int val = a[i];
int j;
for (j = i + 1; j < n && a[j] < val; j++) {
a[j - 1] = a[j];
}
a[j - 1] = val;
}
}
This will sort your array from the right:
67, 7, 3, 2, 1, 9, 5, 45
67, 7, 3, 2, 1, 5, 9, 45
67, 7, 3, 2, 1, 5, 9, 45
67, 7, 3, 1, 2, 5, 9, 45
67, 7, 1, 2, 3, 5, 9, 45
67, 1, 2, 3, 5, 7, 9, 45
1, 2, 3, 5, 7, 9, 45, 67

Looking for non-recursive algorithm for visiting all k-combinations of a multiset in lexicographic order

More specifically, I'm looking for an algorithm A that takes as its inputs
a sorted multiset M = {a1, a2, …, an } of non-negative integers;
an integer 0 &leq; k &leq; n = |M |;
a "visitor" callback V (taking a k-combination of M as input);
(optional) a sorted k-combination K of M (DEFAULT: the k-combination {a1, a2, …, ak }).
The algorithm will then visit, in lexicographic order, all the k-combinations of M, starting with K, and apply the callback V to each.
For example, if M = {0, 0, 1, 2}, k = 2, and K = {0, 1}, then executing A(M, k, V, K ) will result in the application of the visitor callback V to each of the k-combinations {0, 1}, {0, 2}, {1, 2}, in this order.
A critical requirement is that the algorithm be non-recursive.
Less critical is the precise ordering in which the k-combinations are visited, so long as the ordering is consistent. For example, colexicographic order would be fine as well. The reason for this requirement is to be able to visit all k-combinations by running the algorithm in batches.
In case there are any ambiguities in my terminology, in the remainder of this post I give some definitions that I hope will clarify matters.
A multiset is like a set, except that repetitions are allowed. For example, M = {0, 0, 1, 2} is a multiset of size 4. For this question I'm interested only in finite multisets. Also, for this question I assume that the elements of the multiset are all non-negative integers.
Define a k-combination of a multiset M as any sub-multiset of M of size k. E.g. the 2-combinations of M = {0, 0, 1, 2} are {0, 0}, {0, 1}, {0, 2}, and {1, 2}.
As with sets, the ordering of a multiset's elements does not matter. (e.g. M can also be represented as {2, 0, 1, 0}, or {1, 2, 0, 0}, etc.) but we can define a canonical representation of the multiset as the one in which the elements (here assumed to be non-negative integers) are in ascending order. In this case, any collection of k-combinations of a multiset can itself be ordered lexicographically by the canonical representations of its members. (The sequence of all 2-combinations of M given earlier exhibits such an ordering.)
UPDATE: below I've translated rici's elegant algorithm from C++ to JavaScript as faithfully as I could, and put a simple wrapper around it to conform to the question's specs and notation.
function A(M, k, V, K) {
if (K === undefined) K = M.slice(0, k);
var less_than = function (a, b) { return a < b; };
function next_comb(first, last,
/* first_value */ _, last_value,
comp) {
if (comp === undefined) comp = less_than;
// 1. Find the rightmost value which could be advanced, if any
var p = last;
while (p != first && ! comp(K[p - 1], M[--last_value])) --p;
if (p == first) return false;
// 2. Find the smallest value which is greater than the selected value
for (--p; comp(K[p], M[last_value - 1]); --last_value) ;
// 3. Overwrite the suffix of the subset with the lexicographically
// smallest sequence starting with the new value
while (p !== last) K[p++] = M[last_value++];
return true;
}
while (true) {
V(K);
if (!next_comb(0, k, 0, M.length)) break;
}
}
Demo:
function print_it (K) { console.log(K); }
A([0, 0, 0, 0, 1, 1, 1, 2, 2, 3], 8, print_it);
// [0, 0, 0, 0, 1, 1, 1, 2]
// [0, 0, 0, 0, 1, 1, 1, 3]
// [0, 0, 0, 0, 1, 1, 2, 2]
// [0, 0, 0, 0, 1, 1, 2, 3]
// [0, 0, 0, 0, 1, 2, 2, 3]
// [0, 0, 0, 1, 1, 1, 2, 2]
// [0, 0, 0, 1, 1, 1, 2, 3]
// [0, 0, 0, 1, 1, 2, 2, 3]
// [0, 0, 1, 1, 1, 2, 2, 3]
A([0, 0, 0, 0, 1, 1, 1, 2, 2, 3], 8, print_it, [0, 0, 0, 0, 1, 2, 2, 3]);
// [0, 0, 0, 0, 1, 2, 2, 3]
// [0, 0, 0, 1, 1, 1, 2, 2]
// [0, 0, 0, 1, 1, 1, 2, 3]
// [0, 0, 0, 1, 1, 2, 2, 3]
// [0, 0, 1, 1, 1, 2, 2, 3]
This, of course, is not production-ready code. In particular, I've omitted all error-checking for the sake of readability. Furthermore, an implementation for production will probably structure things differently. (E.g. the option to specify the comparator used by next_combination's becomes superfluous here.) My main aim was to keep the ideas behind the original algorithm as clear as possible in a piece of functioning code.
I checked the relevant sections of TAoCP, but this problem is at most an exercise there. The basic idea is the same as Algorithm L: try to "increment" the least significant positions first, filling the positions after the successful increment to have their least allowed values.
Here's some Python that might work but is crying out for better data structures.
def increment(M, K):
M = list(M) # copy them
K = list(K)
for x in K: # compute the difference
M.remove(x)
for i in range(len(K) - 1, -1, -1):
candidates = [x for x in M if x > K[i]]
if len(candidates) < len(K) - i:
M.append(K[i])
continue
candidates.sort()
K[i:] = candidates[:len(K) - i]
return K
return None
def demo():
M = [0, 0, 1, 1, 2, 2, 3, 3]
K = [0, 0, 1]
while K is not None:
print(K)
K = increment(M, K)
In iterative programming, to make combinations of K size you would need K for loops. First we remove the repetitions from the sorted input, then we create an array that represents the for..loop indices. While the indices array doesn't overflow we keep generating combinations.
The adder function simulates the pregression of counters in a stacked for loop. There is a little bit of room for improvement in the below implementation.
N = size of the distinct input
K = pick size
i = 0 To K - 1
for(var v_{i0} = i_{0}; v_{i} < N - (K - (i + 1)); v_{i}++) {
...
for(var v_{iK-1} = i_{K-1}; v_{iK-1} < N - (K - (i + 1)); v_{iK-1}++) {
combo = [ array[v_{i0}] ... array[v_{iK-1}] ];
}
...
}
Here's the working source code in JavaScript
function adder(arr, max) {
var k = arr.length;
var n = max;
var carry = false;
var i;
do {
for(i = k - 1; i >= 0; i--) {
arr[i]++;
if(arr[i] < n - (k - (i + 1))) {
break;
}
carry = true;
}
if(carry === true && i < 0) {
return false; // overflow;
}
if(carry === false) {
return true;
}
carry = false;
for(i = i + 1; i < k; i++) {
arr[i] = arr[i - 1] + 1;
if(arr[i] >= n - (k - (i + 1))) {
carry = true;
}
}
} while(carry === true);
return true;
}
function nchoosekUniq(arr, k, cb) {
// make the array a distinct set
var set = new Set();
for(var i=0; i < arr.length; i++) { set.add(arr[i]); }
arr = [];
set.forEach(function(v) { arr.push(v); });
//
var n = arr.length;
// create index array
var iArr = Array(k);
for(var i=0; i < k; i++) { iArr[i] = i; }
// find unique combinations;
do {
var combo = [];
for(var i=0; i < iArr.length; i++) {
combo.push(arr[iArr[i]]);
}
cb(combo);
} while(adder(iArr, n) === true);
}
var arr = [0, 0, 1, 2];
var k = 2;
nchoosekUniq(arr, k, function(set) {
var s="";
set.forEach(function(v) { s+=v; });
console.log(s);
}); // 01, 02, 12

Make 2D array into 1D array in Processing

I am trying to flatten a two dimensional array into a one dimensional array. This is what I currently have. I would like the flatten out my array so that the one dimensional array looks like this
int[] oneDim = {1, 2, 3, 4, 5, 6, 7, 8 ,9 ,10, 11, 12};
This is what I currently have. I dont really know how to go about doing this. All help and input is appreciated.
void setup() {
int[][] twoDim = { {1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12} };
int[] oneDim = new int[twoDim.length];
for (int i = 0; i < twoDim.length; i++) {
for (int j = 0; j < twoDim[i].length; j++) {
oneDim[j] += twoDim[j][i];
}
}
println(oneDim);
}
int[][] twoDim = { {1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12} };
int x = twoDim.length;
int y = twoDim[0].length;
int[] oneDim = new int[x*y];
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
oneDim[i*y + j] = twoDim[i][j];
}
}
println(oneDim);
Here's a hint: the usual formula for mapping two dimensions to one is: width*y + x, where width is the number of elements in each row (4, in your case, as given by twoDim[i].length, assuming they are all the same length), 'x' is the iterator over columns (j, in your case), and y is the iterator over rows (i for you).
You will want to check that the size of your one dimensional array is sufficient to accept all the elements of twoDim. It doesn't look big enough as it is - it needs to be twoDim[i].length * twoDim.length elements long, at least.
You're currently writing the same row of data over and over again, because you're assigning to oneDim[j] in the inner loop for every iteration of the outer loop. Try assigning to oneDim (once it is of appropriate size) using the formula I suggested at the start of this answer instead.

Resources