I wonder what is the best algorithm to sort binary array with least swaps? (having array eg [0,0,0,1,0,1,0] to become [0,0,0,0,0,1,1]).
I implemented some bubble sorts but wonder what is the optimisation for those?
My code is in python, but any language is welcomed, if anyone has a solution for the least swaps that would really improve my program and i would really appreciate!!
If you really want to do it using swaps, you can start from both ends and swap the 1s you find on the left side going forward with the 0s you find on the right side going backward.
A = [0,0,0,1,0,1,0]
left1s = (i for i,b in enumerate(A) if b==1)
right0s = (len(A)-j for j,b in enumerate(reversed(A),1) if b==0)
swapCount = 0
for i,j in zip(left1s,right0s):
if i>=j:break
A[i],A[j] = A[j],A[i]
swapCount += 1
print(A) # [0, 0, 0, 0, 0, 1, 1]
print(swapCount,"swaps") # 1 swaps
Note that the same logic can be written without the use of iterators and zip:
A = [0,0,0,1,0,1,0]
swaps = 0
f,b = 0,len(A)-1 # forward and backward indexes
while f<b: # until forward meets backward
if A[f]==0: f += 1 # skip 0s forward
elif A[b]==1: b -= 1 # skip 1s backward
else: swaps,A[f],A[b] = swaps+1,A[b],A[f] # swap misplaced bits
print(A) # [0, 0, 0, 0, 0, 1, 1]
print(swaps,"swaps") # 1 swaps
If you don't want to use .sort() or similar stuff I can think of that solution:
arr = [0,0,0,1,0,1,0]
print([0] * arr.count(0) + [1] * arr.count(1))
Which ends up in [0, 0, 0, 0, 0, 1, 1]
Edit:
l = len(arr)
z = arr.count(0)
print([0]*z + [1] * (l - z))
seems to be faster with timeit.timeit
You don't need to sort a binary array, especially with python's small integer interning.
The count of ones is given by
ones = sum(lst)
The count of zeros is the length minutes that:
zeros = len(lst) - ones
You can construct the right list with
[0] * zeros + [1] * ones
Many languages have their own implementation.
Example for javascript:
[0,0,0,1,0,1,0].sort();
returns
[ 0, 0, 0, 0, 0, 1, 1 ]
Edited: adding my own implementation on javascript.
The strategy was navigate from the begin and stop when found 1, and then navigate from the end to found 0 to swap.
It's one of multiple possible implementations.
function sortBinaryArray(binArr){
let i = 0;
let j = binArr.length;
let swapCount = 0;
while(i < j){
if(binArr[i] === 0) {
// found 0 on position i. Its sorted until now.
i++;
continue;
}
// Found 1 on posittion i. Search from the end for 0 to swap
j--;
while(i < j){
if (binArr[j] === 0) {
// Found position to swap
binArr[i] = 0;
binArr[j] = 1;
i++;
swapCount++;
break;
}
j--
}
}
console.log('swapCount='+swapCount);
}
var myArr = [0,0,0,1,0,1,0];
sortBinaryArray(myArr);
console.log(myArr)
output:
swapCount=1
Array(7) [ 0, 0, 0, 0, 0, 1, 1 ]
Related
I want the program in python to print all the possible combination of a number or characters of a string.
for example:
123
213
231
132
321
312
the amount is !3 but I'm not sure how to approch it.
i thought of using recursion but I can't figure out how to implement it.
thanks in advance!
itertools.permutations can do this for you.
import itertools
for c in itertools.permutations('123'):
print(''.join(c))
We assume
X="123"
We want to find all the possible combinations.
import itertools
for c in itertools.permutations(X) :
print(''.join(c))
If you'd rather not import the itertools library you can use the code from GeeksForGeeks:
def printCombination(arr, n, r):
data = [0]*r;
combinationUtil(arr, data, 0,
n - 1, 0, r);
def combinationUtil(arr, data, start,
end, index, r):
if (index == r):
for j in range(r):
print(data[j], end = " ");
print();
return;
i = start;
while(i <= end and end - i + 1 >= r - index):
data[index] = arr[i];
combinationUtil(arr, data, i + 1,
end, index + 1, r);
i += 1;
arr = [1, 2, 3, 4, 5];
r = 3;
n = len(arr);
printCombination(arr, n, r);
i have this method which create a list of lists which contain zeros and one.
for example the output for (unit = 3) is: [[1,0,0],[0,1,0],[0,0,1]]
how can i do it in less lines with list comprehension? I think that one line its enough.
major_list = [] # contains lists full off zeros and ones and at the end converted to a matrix
for i in range(unit):
major_list.append([0] * unit)
major_list[i][i] = 1
You can't get any faster than using numpy.identity():
np.identity(3)
Code:
import numpy as np
unit = 3
major_array = np.identity(unit)
With a list comphrension you can join 3 sublist
major_list = [[0] * i + [1] + [0] * (unit - i - 1) for i in range(unit)]
print(major_list)
Or better use a performante way with numpy
major_list = numpy.identity(3)
print(major_list)
Testing the performance of the different methods suggested here, and assuming the required final result is a list of lists (and not numpy array), the fastest, with 2.091 seconds to unit = 10k is:
major_list = [[0] * i + [1] + [0] * (unit - i - 1) for i in range(unit)]
The numpy method becomes:
major_list = numpy.identity(unit).astype(int).tolist()
And is second fastest with 2.359 sec.
My method:
major_list = [[1 if i == index else 0 for i in range(unit)]
for index in range(unit)]
Is far behind with 6.960 sec.
And last:
major_list = [[int(c==r) for c in range(unit)] for r in range(unit)]
With 17.732 sec
If by optimize you mean reduce the number of lines (not necessarily make it faster), you can use the following:
unit = 4
major_list = [
[ 0 ] * (i) +
[ 1 ] +
[ 0 ] * (unit - i - 1)
for i in range(unit)
]
for i in major_list:
print(i)
[1, 0, 0, 0]
[0, 1, 0, 0]
[0, 0, 1, 0]
[0, 0, 0, 1]
The following makes it rather concise:
major_list = [[int(c==r) for c in range(unit)] for r in range(unit)]
This puts 1 where column index equals row index, 0 everywhere else.
You can try this:
def frame_matrix(unit):
return [[int(1) if i==j else 0 for i in range(unit)] for j in range(unit)]
I'm currently trying to randomize a list of 0s and 1s which should give a random order of zeros and ones with the following constraints:
1/3 of the items have to be 1s (respectively 2/3 are 0s)
No more than two 1s should occur consecutively
No more than four zeros should occur consecutively
I have worked on an option, but it did not exactly turn out to be what I need. Here's my option:
for prevItem, nextItem in enumerate(WordV[: -1]):
if nextItem == WordV[prevItem+1] and WordV[prevItem+1] == WordV[prevItem+2] and nextItem ==1:
WordV[prevItem+2] = 0
if nextItem == WordV[prevItem+1] and WordV[prevItem+1] == WordV[prevItem+2] and WordV[prevItem+2] == WordV[prevItem+3] and WordV[prevItem+3] == WordV[prevItem+4] and nextItem == 0:
WordV[prevItem+2] = 1
# Check the number of ones & zeros
print(WordV)
ones= WordV.count(1)
zeros= WordV.count(0)
print(ones, zeros)
Currently, the number of ones and zeros does not add up to a proportion of 1/3 to 2/3 because the constraints replace numbers. The WordV list is a list containing 24 ones and 48 zeros that is shuffled randomly (with random.shuffle(WordV)).
Is there a smarter (and more correct) way to integrate the constraints into the code?
import numpy as np
def consecutive(data, stepsize=0):
return np.split(data, np.where(np.diff(data) != stepsize)[0]+1)
def check(list_to_check):
groups = consecutive(list_to_check)
for group in groups:
if group[0] == 1 and group.size > 2:
return True
if group[0] == 0 and group.size > 4:
return True
wordv = np.array([1]*24+[0]*48)
while check(wordv):
np.random.shuffle(wordv)
wordv will contain something like:
array([0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1,
0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
0, 0, 1, 0, 1, 0])
The consecutive function will split the data in groups containing the same element:
[ins] In [32]: consecutive([1,1,1,0,0,1])
Out[32]: [array([1, 1, 1]), array([0, 0]), array([1])]
The check will check both conditions you specified and we will shuffle the list until we meet the conditions
You could try an optimization approach: Start with the list holding the elements in the right proportion, then keep swapping random elements until you get the desired results. In each turn, check the number of too-long streaks of 0s or 1s and always keep the better one of the original or the mutated list.
import itertools, random
def penalty(lst):
return sum(1 for k, g in itertools.groupby(lst)
if k == 0 and len(list(g)) > 4 or k == 1 and len(list(g)) > 2)
def constrained_shuffle(lst):
# penalty of original list
p = penalty(lst)
while p > 0:
# randomly swap two elements, get new penalty
a, b = random.randrange(len(lst)), random.randrange(len(lst))
lst[a], lst[b] = lst[b], lst[a]
p2 = penalty(lst)
if p2 > p:
# worse than before, swap back
lst[a], lst[b] = lst[b], lst[a]
else:
p = p2
lst = [0] * 20 + [1] * 10
random.shuffle(lst)
constrained_shuffle(lst)
print(lst)
For 200 0s and 100 1s this will take a few hundred to a few thousand iterations until it finds a valid list, which is okay. For lists with thousands of elements this is rather too slow, but could probably be improved by memorizing the positions of the too-long streaks and preferrably swapping elements within those.
About the "randomness" of the approach: Of course, it is less random than just repeatedly generating a new shuffled list until one fits the constraints, but I don't see how this will create a bias for or against certain lists, as long as those satisfy the constraints. I did a short test, repeatedly generating shuffled lists and counting how often each variant appears:
counts = collections.Counter()
for _ in range(10000):
lst = [0] * 10 + [1] * 5
random.shuffle(lst)
constrained_shuffle(lst)
counts[tuple(lst)] += 1
print(collections.Counter(counts.values()).most_common())
[(7, 197), (6, 168), (8, 158), (9, 157), (5, 150), (10, 98), (4, 92),
(11, 81), (12, 49), (3, 49), (13, 43), (14, 23), (2, 20), (15, 10),
(1, 8), (16, 4), (17, 3), (18, 1)]
So, yes, maybe there are a few lists that are more likely than others (one appeared 18 times, three 17 times, and most others 5-9 times). For 100,000 iterations, the "more likely" lists appear ~50% more often than the others, but still only about 120 times out of those 100,000 iterations, so I'd think that this is not too much of a problem.
Without the initial random.shuffle(lst) there are more lists what appear much more often than the average, so this should not be skipped.
I don't really know python, so I'll give you pseudocode:
int length;
int[] onesAndZeros = new int[length];
for(int i: onesAndZeros) { // generate a random list
i = random(0, 1);
}
int zeroCount() { // correct the ratio
int c;
for(int i: onesAndZeros) {
if(i == 0) {
c++;
}
}
return c;
}
int wantedZeros;
if(zeroCount() / (length - zeroCount()) != 2) { // you should probably check a small interval, but this answer is already long
int a = 2*(length - zeroCount()) - zeroCount(); // I will include the math if necessary
wantedZeros = zeroCount() + a;
}
while(zeroCount() != wantedZeros) {
boolean isLess = zeroCount < wantedZeros;
if(isLess) {
onesAndZeros[random(0, length - 1)] = 0;
} else {
onesAndZeros[random(0, length - 1)] = 0;
}
}
string isCorrect() { // fix the 2 1s and 4 0s
for(int i = 0; i < length; i++) {
if(onesAndZeros[i] == 0 &&
onesAndZeros[i + 1] == 0 &&
onesAndZeros[i + 2] == 0 &&
onesAndZeros[i + 3] == 0 &&
onesAndZeros[i + 4] == 0) { // be sure not to go out of bounds!
return "0" + i;
} else
if(onesAndZeros[i] == 1 &&
onesAndZeros[i + 1] == 1 &&
onesAndZeros[i + 2] == 1) {
return "1" + i;
} else {
return "a";
}
}
}
void fix(int type, int idx) {
if(type == 0) {
onesAndZeros[idx + 4] = 1;
} else {
onesAndZeros[idx + 2] = 0;
}
}
string corr = isCorrect();
while(length(corr) >= 2) { // note: this step will screw up the ones/zeros ratio a bit, if you want to restore it, consider running the last 2 steps again
if(corr[0] == '0') {
fix(0, toInt(removeFirstChar(corr)));
} else {
fix(1, toInt(removeFirstChar(corr)));
}
}
// done!
I'm well aware that this can be greatly optimized and cleaned up, depending on the language. But this is more of a solid base to build upon.
I just did a coding challenge for a company and was unable to solve this problem. Problem statement goes like:
Given an array of integers, find the number of subsequences in the array whose sum is divisible by k, where k is some positive integer.
For example, for [4, 1, 3, 2] and k = 3, the solution is 5. [[3], [1, 2], [4,3,2], [4,2], [1,3,2]] are the subsequences whose sum is divisible by k, i.e. current_sum + nums[i] % k == 0, where nums[i] is the current element in the array.
I tried to solve this recursively, however, I was unable to pass any test cases. My recursive code followed something like this:
def kSum(nums, k):
def kSum(cur_sum, i):
if i == len(nums): return 0
sol = 1 if (cur_sum + nums[i]) % k == 0 else 0
return sol + kSum(cur_sum, i+1) + kSum(cur_sum + nums[i], i+1)
return kSum(0, 0)
What is wrong with this recursive approach, and how can I correct it? I'm not interested in an iterative solution, I just want to know why this recursive solution is wrong and how I can correct it.
Are you sure that is not the case test? For example:
[4, 1, 3, 2], k = 3
has
4+2 = 6, 1+2=3, 3, 1+2+3=6, 4+2+3 = 9
So, your function is right (it gives me 5) and I don't see a major problem with your function.
Here is a javascript reproduction of what you wrote with some console logs to help explain its behavior.
function kSum(nums, k) {
let recursive_depth = 1;
function _kSum(cur_sum, i) {
recursive_depth++;
if (i == nums.length) {
recursive_depth--;
return 0;
}
let sol = 0;
if (((cur_sum + nums[i]) % k) === 0) {
sol = 1;
console.log(`Found valid sequence ending with ${nums[i]} with sum = ${cur_sum + nums[i]} with partial sum ${cur_sum} at depth ${recursive_depth}`);
}
const _kSum1 = _kSum(cur_sum, i+1);
const _kSum2 = _kSum(cur_sum + nums[i], i+1);
const res = sol + _kSum1 + _kSum2;
recursive_depth--;
return res;
}
return _kSum(0, 0);
}
let arr = [4, 1, 3, 2], k = 3;
console.log(kSum(arr, k));
I think this code actually gets the right answer. I'm not fluent in Python, but I might have inadvertently fixed a bug in your code though by adding parenthesis around (cur_sum + nums[i]) % k
It seems to me that your solution is correct. It reaches the answer by trying all subsequences, which has 2^n complexity. We could formulate it recursively in an O(n*k) search space, although it could be more efficient to table. Let f(A, k, i, r) represent how many subsequences leave remainder r when their sum is divided by k, using elements up to A[i]. Then:
function f(A, k, i=A.length-1, r=0){
// A[i] leaves remainder r
// when divided by k
const c = A[i] % k == r ? 1 : 0;
if (i == 0)
return c;
return c +
// All previous subsequences
// who's sum leaves remainder r
// when divided by k
f(A, k, i - 1, r) +
// All previous subsequences who's
// sum when combined with A[i]
// leaves remainder r when
// divided by k
f(A, k, i - 1, (k + r - A[i]%k) % k);
}
console.log(f([1,2,1], 3));
console.log(f([2,3,5,8], 5));
console.log(f([4,1,3,2], 3));
console.log(f([3,3,3], 3));
I'm completing a google foobar challenge, but for the life of me, I can't pass the 4th test case, here is the challenge:
You need to figure out which sets of panels in any given array you can take offline to repair while still maintaining the maximum amount of power output per array, and to do THAT, you'll first need to figure out what the maximum output of each array actually is. Write a function answer(xs) that takes a list of integers representing the power output levels of each panel in an array, and returns the maximum product of some non-empty subset of those numbers. So for example, if an array contained panels with power output levels of [2, -3, 1, 0, -5], then the maximum product would be found by taking the subset:
xs[0] = 2, xs[1] = -3, xs[4] = -5, giving the product 2*(-3)*(-5) = 30. So answer([2,-3,1,0,-5]) will be "30".
Each array of solar panels contains at least 1 and no more than 50 panels, and each panel will have a power output level whose absolute value is no greater than 1000 (some panels are malfunctioning so badly that they're draining energy, but you know a trick with the panels' wave stabilizer that lets you combine two negative-output panels to produce the positive output of the multiple of their power values). The final products may be very large, so give the answer as a string representation of the number.
Here are some given test cases:
Test cases
Inputs:
(int list) xs = [2, 0, 2, 2, 0]
Output:
(string) "8"
Inputs:
(int list) xs = [-2, -3, 4, -5]
Output:
(string) "60"
And here is my code:
def product_of_values(lst):
product = 1
if len(lst) > 0:
for x in lst:
product *= x
return product
def answer(xs):
# two seperate list for positive and negative values
positive_list = [x for x in xs if x > 0]
negative_list = [x for x in xs if x < 0]
pos_product = product_of_values(pos_list)
# multiplication of an even number of negatives == positive value
if len(negative_list) % 2 == 0:
negative_product = product_of_values(negative_list)
# if length of negative_list is odd, pop value closest to zero
else:
neg_list.remove(max(neg_list))
neg_product = product_of_values(neg_list)
# If there is only one negative value in the negative_list, return 0.
if len(pos_list) < 1 and len(neg_list) <= 1:
return '0'
else:
return str(neg_product * pos_product)
am I missing something obvious?
#edi_allen I am also facing the same problem. I have written the code in java, visible test cases are passing in my compiler, but failing at foobar. How did you overcome this? Below is my code:
public static String solution(int[] xs) {
if(xs.length < 1 || xs.length > 50) {
return "0";
}
Arrays.parallelSort(xs);
for(int i = 1; i < xs.length ; i++) {
if(xs[i] < 0 && xs[i-1] < 0) {
xs[i-1] = Math.abs(xs[i-1]);
xs[i] = Math.abs(xs[i]);
}
}
BigInteger prod = null;
for(int i = 0; i < xs.length ; i++) {
if(Math.abs(xs[i]) > 1000) {
return "0";
}
else if(xs[i] <= 0) {
continue;
}
else if(prod == null){
prod = new BigInteger(String.valueOf(xs[i]));
}
else {
prod = prod.multiply(new BigInteger(String.valueOf(xs[i])));
}
}
if(prod == null) {
return "0";
}
return prod.toString();
}
Maybe its the time complexity that is problem here.
For the product try this -
from operator import mul
reduce(mul, list, 1)