Algorithm for finding if an array is balanced [closed] - python

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I'm trying to create a program that will create a 10 element array and then assign random values to each element. I then want the program to tell if the array is balanced. By balanced I mean, is there anywhere in the array values that at a certain element the sum of the values in the elements are equal to the sum of the array values in the elements greater than that current element.
Example
Element (1,2,3,4) Values (2,1,3,0)
The program would then display that elements 1-2 are balanced to elemtns 3-4, because they both equal 4.
So far I have
import random
size = 10
mean = 0
lists = [0] * size
for i in range(size):
var = random.randint(0,4)
lists[i] = var
for i in lists:
mean += i
avg = (mean)/(size)
I figured the only way the elements could be balanced is if the values average is equal to 2, so I figured that's how I should start.
I'd appreciate any help in the right direction.

If I understand the question, the simplest solution is something like this:
def balanced(numbers):
for pivot in range(len(numbers)):
left_total = sum(numbers[:pivot])
right_total = sum(numbers[pivot:])
if left_total == right_total:
return pivot
return None
For example:
>>> numbers = [2, 1, 3, 0]
>>> balanced(numbers)
2
>>> more_numbers = [2, 1, 3, 4]
>>> balanced(numbers)
(That didn't print anything, because it returned None, meaning there is no pivot to balance the list around.)
While this is the simplest solution, it's obviously not the most efficient, because you keep adding the same numbers up over and over.
If you think about it, it should be pretty easy to figure out how to keep running totals for left_total and right_total, only calling sum once.
def balanced(numbers):
left_total, right_total = 0, sum(numbers)
for pivot, value in enumerate(numbers):
if left_total == right_total:
return pivot
left_total += value
right_total -= value
return None
Finally, here's how you can build a program around it:
size = 10
numbers = [random.range(4) for _ in range(size)]
pivot = balanced(numbers)
if pivot is None:
print('{} is not balanced'.format(numbers))
else:
print('{} is balanced, because elements 1-{} equal {}-{}'.format(
numbers, pivot+1, pivot+2, size+1))

A good data structure to know about for this kind of problem is an array that has the cumulative sum. element[j] - element[i] is the sum from i to j in the original series. If you have the original series [1, 2, 3, 4], the cumulative series is [0, 1, 3, 6, 10]. The sum up to the i position in the original series is element[i] - element[0]. For this problem, we are interested in only a sum starting at 0, so this is a bit of overkill but, again, more fully useful for other problems.
Here is code to make a cumulative sum:
def cumulative_sum(series):
s = [0]
for element in series:
s.append(element + s[-1])
return s
Given that, we can find the pivot point with this code:
def find_pivot(series):
cs = cumulative_sum(series)
total = cs[-1]
even_total = not (total & 1)
if even_total:
target = total // 2
for i, element in enumerate(cs[1:]):
if element == target:
return i + 1
return -1
Notice that it is not necessary to try dividing the series if we know the series sums to an odd number: there cannot be a pivot point then.
Alternatively, you can write find_pivot like this:
def find_pivot(series):
cs = cumulative_sum(series)
total = cs[-1]
even_total = not (total & 1)
if even_total:
target = total // 2
try:
return cs.index(target)
except ValueError:
return -1
return -1
It has the advantage that the looping is not done explicitly in python but in C code in the standard library.
Trying the code out:
def test():
for i in range(1, 30):
test_values = range(i)
j = find_pivot(test_values)
if j >= 0:
print "{0} == {1}".format(test_values[:j], test_values[j:])
And we get this output:
[0] == []
[0, 1, 2] == [3]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] == [15, 16, 17, 18, 19, 20]

Related

How to fill the bigger square with smaller squares effectively?

I need to write in python3 a function that fills the bigger square with smaller squares basing on the input.
The input is a list of positive integers. Each integer is the number of squares per row. So the list [3, 8, 5, 2] means I got 4 rows of squares where first one has 3 squares, second one 8 and so on. All squares in all rows are of the same size.
The output should be description of rows distribution in the form of list of lists.
The thing is that on the output there can not be empty rows. So effectively the number of columns can not be greater than the number of rows. The rows can be split though into two or more rows. So for example for the list [3, 8, 5, 2] the function should return [[3], [5, 3], [5], [2]]:
AAA
BBBBB
BBB
CCCCC
DD
and for input [14,13,2,12] it should return [[7,7], [7,6], [2], [7,5]]:
AAAAAAA
AAAAAAA
BBBBBBB
BBBBBB
CC
DDDDDDD
DDDDD
As we can see, the number of rows and columns is in both examples equal. Of course it's not always possible but the lesser difference between the number of columns and rows, the more efficient the algorythm is - the better the square is filled. In general we aim to get as many columns as possible and as little rows as possible.
And here is the issue - the above examples used 4 input rows - the input list can have a lot of more elements (for example 200 input rows). And the problem is to find optimial way to split the rows (for example if i should split 18 as 9+9 or 6+6+6 or 7+7+4 or maybe 5+5+5+3). Because every time i split the rows basing on available columns (that depend on the number of used rows), I get more output rows and therefore I am able to use more additional available columns - and I fall into some weird loop or recursion.
I'm sorry if there is some easy solution that I don't see and thank you in advance for help <3
EDIT: Here I include example function that simply ignores the fact that the number of rows increases and just treats the number of input rows as maximum amount of columns possible:
def getSquare(x):
output = list()
ln = len(x)
for i in x:
if i <= ln:
output.append([i])
else:
split = list()
nrows = i // ln
for j in range(nrows):
split.append(ln)
if i % ln:
split.append(i % ln)
output.append(split)
return output
print(getSquare([14, 13, 2, 12]))
# returns [[4, 4, 4, 2], [4, 4, 4, 1], [2], [4, 4, 4]]
# so 4 columns and 12 rows
# columns - maximum number in the matrix
# rows - number of all elements in the matrix (length of flattened output)
# while it should return: [[7,7], [7,6], [2], [7,5]]
# so 7 columns and 7 rows
#(nr of columns should be not larger but as close to the number of rows as possible)
EDIT2: It doesn't have to return perfect square - just something as close to square as possible - for example for [4,3,3] it should return [[3,1],[3]
,[3]] while for extreme cases like [1,1,1] it should just return [[1],[1],[1]]
list = [3, 8, 5, 2] #As close to a Square as possible
def getSquare(list):
for i in range(1, max(list)+1):
output = []
num = 0
for j in list:
output.append([i]*(j//i))
num += j//i
if j%i != 0:
output[-1].append(j%i)
num += 1
if num == i:
return output
i = int( sum(list) ** (1/2) // 1)
output = []
for j in list:
output.append([i]*(j//i))
num += j//i
if j%i != 0:
output[-1].append(j%i)
num += 1
return output
for i in getSquare(list):
for j in i:
print("*"*j)
Here I just repeat the splitting process of the list until i and num become same.
Essentially when you decrease width, you increase number of rows (vice versa is also true: when you increase width, you decrease number of rows), that's why you want to as far as it's possible equalise width and height, because that would get you minimum area of covering square. From this point of view your problem looks like ternary search: minimize maximum of resulting width and height.
So we perform ternary search over width (fix it) and calculate resulting maximum side of square. Calculating function is pretty obvious:
def get_max_side(l, fixed_width): # O(len(l))
height = 0
for i in l:
height += i // fixed_width
if i % fixed_width:
height += 1
return max(fixed_width, height)
Then use it in a ternary search algorithm to find minimum of get_max_side and restore the answer using found value. Time complexity is O(len(l) * log(max_meaningful_square_width)).
I have improved an answer, adding some stop signs to generally speed up the algorithm. It also gives much more efficient answer when no ideal solution was found.
arr = [14, 13, 2, 12] # as close to a square as possible
def getSquare(lst):
output = []
mx = max(lst)
for cols in range(min(len(lst), mx), mx + 1):
out = []
rows = 0
for j in lst:
ln = j // cols
r = j % cols
out.append([cols] * ln)
rows += ln
if r:
out[-1].append(r)
rows += 1
if rows >= cols:
output = out
else:
break
return output
for i in getSquare(arr):
for j in i:
print("*" * j)

How to append to a list two numbers from within the list that add up to a number in the list?

First, I want to find the highest number in the list which is the second number in the list, then split it in two parts. The first part contains the 2nd highest number, while the second part contains the number from the list that sums to the highest number. Then, return the list
eg: input: [4,9,6,3,2], expected output:[4,6,3,6,3,2] 6+3 sums to 9 which is the highest number in the list
Please code it without itertools.
python
def length(s):
val=max(s)
s.remove(val)
for j in s:
if j + j == val:
s.append(j)
s.append(j)
return s
Here's what I have but it doesn't return what the description states.
Any help would be appreciated as I spent DAYS on this.
Thanks,
The main issue in your code seems to be that you are editing the list s whilst iterating through it, which can cause issues with the compiler and is generally just something you want to avoid doing in programming. A solution to this could be iterating through a copy of the original list.
The second problem is that your program doesn't actually find the second biggest value in the list, just a value which doubles to give you the biggest value.
The final problem (which I unfortunately only noticed after uploading what I thought was a solution) is that the split values are appended to the end of the list rather than to the position where originally the largest value was.
Hopefully this helps:
def length(array):
val = max(array)
idx = array.index(val) # gets the position of the highest value in the array (val)
array.remove(val)
for i in array.copy(): # creates a copy of the original list which we can iterate through without causing buggy behaviour
if max(array) + i == val:
array = array[:idx] + [max(array), i] + array[idx:]
# Redefines the list by placing inside of it: all values in the list upto the previous highest values, the 2 values we got from splitting the highest value, and all values which previously went after the highest value.
return array
This will return None if there is no value which can be added to the second highest value to get the highest value in the given array.
Input:
print(length([1,2,3,4,5]))
print(length([4,8,4,3,2]))
print(length([11,17,3,2,20]))
print(length([11,17,3,2,21]))
Output:
[1, 2, 3, 4, 4, 1]
[4, 4, 4, 4, 3, 2]
[11, 17, 3, 2, 17, 3]
None
Here are the docs on list slicing (which are impossible to understand) and a handy tutorial.
when you say "The first part contains the 2nd highest number" does that mean second highest number from the list or the larger of the two numbers that add up the largest number from list?
Here I assume you just wanted the larger of the two numbers that add up to the largest number to come first.
def length(s:list):
#start by finding the largest value and it's position in the list:
largest_pos = 0
for i in range(len(s)):
if s[i] > s[largest_pos]:
largest_pos = i
# find two numbers that add up to the largest number in the s
for trail in range(len(s)):
for lead in range(trail, len(s)):
if (s[trail] + s[lead]) == s[largest_pos]:
if s[trail] > s[lead]:
s[largest_pos] = s[trail]
s.insert(largest_pos +1, s[lead])
else:
s[largest_pos] = s[lead]
s.insert(largest_pos + 1, s[trail])
return s
# if no two numbers add up to the largest number. return s
return s
Since you are limited to 2 numbers, a simple nested loop works.
def length(s):
val = max(s)
idx = s.index(val)
s.remove(val)
for i in range(len(s) - 1):
for j in range(i + 1, len(s)):
if s[i] + s[j] == val:
s = s[:idx] + [s[i], s[j]] + s[idx:]
return s
print(length([4,9,6,3,2]))
Output:
[4, 6, 3, 6, 3, 2]
I used deque library
first to find the highest element or elements then remove all of them and replace them with second high value and rest like : 9 replace with 6 and 3 in example:
from collections import deque
l = [4, 9, 6, 3, 2]
a = deque(l)
e = a.copy()
s = max(a)
while s in a:
a.remove(s) # remove all highest elements
s2 = max(a) # find second high value
c = s - s2
for i in l:
if i == s:
w = e.index(i) # find index of high values
e.remove(max(e))
e.insert(w, s2)
e.insert(w+1, c)
print(list(e))

How to use recursion to sum up a list of numbers up until a certain index

I have to write a code that makes use of recursion to sum numbers in a list up until the index is equal to a pre-determined integer value. i.e.
list = [1,4,8,9]
int = 2
sum = 1 + 4 (index 0 and 1)
below is my code so far, but I am struggling with the logic with my first if statement and hence it isn't working. I get the error 'int' object has no attribute 'index' Any help would be greatly appreciated (PS very new to coding - so sorry if my code isn't the best)!
# Sum Recursion
def Arecursion(Alist,index):
if index > 0: # if the index point in the list matches the integer return the sum
return Alist[index] + Arecursion(Alist,index-1)
else:
return 0
list_test = [1,4,6,7,10]
int_test = 2
print(Arecursion(list_test,int_test))
You are making it more complex that you need to. You just need a base case — the current index is too big, and the recursion — the value at the current index plus the rest:
def sum_rec(l,max_index, i=0):
if i >= max_index or i >= len(l): # base case
return 0
return l[i] + sum_rec(l, max_index, i+1) # recursion
sum_rec([1, 2, 3, 4], 0)
# 0
sum_rec([1, 2, 3, 4], 1)
# 1
sum_rec([1, 2, 3, 4], 2)
# 3
sum_rec([1, 2, 3, 4], 3)
#6

Print harmonic series for the given series in Python 3

I want to print harmonic series in python as follow but I don't understand how to do it, pls help and it would be nice if you could maybe explain how you did it. I have not tried any code and was not able to find it on the web
The problem
We want to iterate n (1, 2, 3, 4, 5, ...) and pass it in the formula nx/n!, for example user ill define x by this line of code x = int(input("What's the value of x? ")), so image user types number 5, so we need to get: 1*5/1!, 2*5/2!, 3*5/3!, 4*5/4!.
Here is another problem: Python's ! symbol means boolean invert, so !true is equal to false, not factorial.
factorial function in Python
So we need to define function factorial:
def factorial(number):
fact = 1
for n in range(1, number+1):
fact *= n # The same as fact = fact * n
return fact
# TEST OF THE FACTORIAL FUNCTION
# print(f'factorial(3) == 1*2*3 => { factorial(3) == 1*2*3 }')
Limit of the sequence
We actually need to get the nlim number from the user that tells the loop when to stop.
nlim = int(input("What's the limit of the sequence? "))
The sequence
So, we need to get Python evaluate this (if x is equal to 5 and n is increasing from 1 by step 1 to limit nlim): 1*5/factorial(1), 2*5/factorial(2), 3*5/factorial(3) and so on.
results = [] # in this list all the results will be stored
for n in range(1, nlim+1):
results.append((n*x) / factorial(n)) # here comes the formula!
Read sequence
for i, result in enumerate(results):
# enumerate([7, 8, 9]) will give us 2D list with indexes [[0, 7], [1, 8], [2, 9]]
# Then we will iterate this, so on each loop cycle we get [0, 7], then [1, 8] and so on
# if we do following: a, b = [1, 2] then variable a will be 1 and variable b will be 2
print(f'result[{ i }]: { result }')
All the code
def factorial(number):
fact = 1
for n in range(1, number+1):
fact *= n
return fact
x = int(input("What's the value of x? "))
nlim = int(input("What's the limit of the sequence? "))
results = []
for n in range(1, nlim+1):
results.append((n*x) / factorial(n))
for i, result in enumerate(results):
print(f'result[{ i }]: { result }')

Extracting significant values from an array

I'm looking for an efficient way to extract from an array in Python only significant values, for instance, only those 10 times bigger than the rest. The logic (no code) using a very simple case is something like that:
array = [5000, 400, 40, 10, 1, 35] # here the significant value will be 5000.
from i=0 to len.array # to run the procedure in all the array components
delta = array[i] / array [i+1] # to confirm that array[i] is significant or not.
if delta >= 10 : # assuming a rule of 10X significance i.e significance = 10 times bigger than the rest of elements in the array.
new_array = array[i] # Insert to new_array the significant value
elif delta <= 0.1 : # in this case the second element is the significant.
new_array = array[i+1] # Insert to new_array the significant value
at the end new_array will be composed by the significant values, in this case new_array =[5000], but must apply to any kind of array.
Thanks for your help!
UPDATE!!!
Thanks to all for your answers!!! in particular to Copperfield who gave me a good idea about how to do it. Here is the code that's working for the purpose!
array_o = [5000,4500,400, 4, 1, 30, 2000]
array = sorted(array_o)
new_array = []
max_array = max(array)
new_array.append(max_array)
array.remove(max_array)
for i in range(0,len(array)):
delta = max_array / array[i]
if delta <= 10:
new_array.append(array[i])
Does this answer your question?
maxNum = max(array)
array.remove(maxNum)
SecMaxNum = max(array)
if maxNum / SecMaxNum >= 10 :
# take action accordingly
else:
# take action accordingly
your pseudo code can be translate to this function
def function(array):
new_array = []
for i in range(1,len(array)):
delta = array[i-1] / array[i]
if delta >= 10:
new_array.append( array[i-1] )
elif delta <= 0.1:
new_array.append( array[i] )
return new_array
this give this result
>>> function([5000, 400, 40, 10, 1, 35])
[5000, 400, 10, 35]
>>>
Now, what you describe can be done like this in python 3.5+
*rest, secondMax, maxNum = sorted(array)
if maxNum / secondMax >= 10:
# take action accordingly
else:
# take action accordingly
or in previous versions
sortedArray = sorted(array)
if sortedArray[-1] / sortedArray[-2] >= 10:
# take action accordingly
else:
# take action accordingly
(the negative index access the element from last to first, so -1 is the last one, -2 the second last, etc )
I would not adopt the approach of only comparing each value to the one next to it. If the array is unsorted then obviously that's a disaster, but even if it is sorted:
a = [531441, 59049, 6561, 729, 81, 9, 9, 8, 6, 6, 5, 4, 4, 4, 3, 3, 1, 1, 1, 1]
In that example, the "rest" (i.e. majority) of the values are <10, but I've managed to get up into the 6-digit range very quickly with each number only being 9 times the one next to it (so, your rule would not be triggered).
One approach to outlier detection is to subtract the median from your distribution and divide by a non-parametric statistic that reflects the spread of the distribution (below, I've chosen a denominator that would be equivalent to the standard deviation if the numbers were normally distributed). That gives you an "atypicality" score on a standardized scale. Find the large values, and you have found your outliers (any score larger than, say, 3—but you may need to play around a bit to find the cutoff that works nicely for your problem).
import numpy
npstd = numpy.diff(numpy.percentile(a, [16, 84]))/2.0 # non-parametric "standard deviation" equivalent
score = (a - numpy.median(a)) / npstd
outlier_locations, = numpy.where(score > 3) # 3, 4 or 5 might work well as cut-offs

Categories

Resources