python- Solving Round Table (ZCO,2012) - python

N knights are sitting in a circle. Making a dessert for knight i costs C[i]. Find the minimum cost such that for every pair of adjacent knights, at least one gets his dessert. N ≤ 10 ** 6.
Input
There are 2 lines of input. The first line contains a single integer N, the number of seats at the table. The next line contains N space-separated integers, each being the cost of the dessert of a Knight, listed in counterclockwise order around the table.
Output
The output should be a single line containing a single integer, the minimum possible cost for you, the chef.
Problem reference:https://www.codechef.com/ZCOPRAC/problems/ZCO12004
.I have tried this using DP, my code
n=int(input())
a=[int(i) for i in input().split()]
def ram(x):
m=x[0]
k=0
for i in range(2,n):
if k==0:
m+=min(x[i],x[i-1])
if min(x[i],x[i-1]) ==x[i]:
k=1
else:
k=0
else:
k=0
continue
return m
b1=ram(a)
a.insert(0,a[n-1])
a.pop(n)
b2=ram(a)
print(min(b1,b2))
But unfortunately, this is a wrong answer, please find the fault.It is advised to consider time complexity, less than 1 sec.
edit:
n=int(input())
a=[int(i) for i in input().split()]
cost1=cost2=[]
if n==1:
print(a[0])
elif n==2:
print(min(a[0],a[1]))
else:
cost1.append(a[0])
cost1.append(a[1])
for j in range(2,n):
cost1.append(a[j]+min(cost1[j-1],cost1[j-2]))
cost2.append(a[n-1])
cost2.append(a[n-2])
for k in range(2,n):
cost2.append(a[n-k-1]+min(cost2[k-1],cost2[k-2]))
print(min(cost1[n-1],cost2[n-1]))

This solution to this problem basically has to take care of 2 states.
Consider you are currently at index i. Now you have to decide whether you want to select the element of index i in your final sum.
The states are as follows:
1) If you decide that element at index i should included in final sum, then it does not matter that the element at previous index, i.e. i-1, is included or not.
2) If you decide that element at index i should not be included in final sum, then it is mandatory that the element at previous index, i.e. i-1, is included.
In your solution, you are taking care of only state 1, but not of state 2. So you will have to maintain 2 variables for optimal intermediate answers at each index.
Here is the sample code:
function calculate(int arr[], int start, int end){
dp[start][0] = arr[start];
dp[start][1] = 0LL;
for(int i=start+1;i<=end;i++){
dp[i][1] = dp[i-1][0]; //State 2
dp[i][0] = arr[i] + min( dp[i-1][1], dp[i-1][0] ); //State 1
}
return min( dp[end][0], dp[end][1] );
}
Note: dp array is a 2D array that stores the intermediate optimal answers.
dp[i][1] = Optimal answer by not including the element.
dp[i][0] = Optimal answer by including the element.

Related

Easy algorithm-Leet code- Maximum sub array

Struggling to wrap my head around this.
Maximum Subarray
Easy
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
A subarray is a contiguous part of an array.
Example 1:
Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Example 2:
Input: nums = [1]
Output: 1
Example 3:
Input: nums = [5,4,-1,7,8]
Output: 23
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
subarray1=[]
subarray2=[]
for n in nums:
subarray1.append(sum(nums[nums.index(n):]))
nums2=nums[::-1]
subarray2.append(sum(nums2[nums.index(n):]))
para1=subarray1.index(max(subarray1))
para2=len(nums)-subarray2.index(max(subarray2))
ans=sum(nums[para1:para2])
if sum(nums)>ans :
ans=sum(nums)
if len(nums)==2 and sum(nums)< nums[0] or nums[1] :
ans=max(nums)
return ans
I'm don't understand the iterative logic and the answers from vids are coming up wrong.
My logic is to create an array summing the input array from both sides and use the index of max values on those 2 arrays to figure out the maximum sum sub array parameters.
My answer is supposedly wrong when copied onto leet code https://leetcode.com/problems/maximum-subarray/
Been trying for hours, it's marked as easy. Im sure there is an easy iterative way of doing it but everything I've search is wrong so far.
There is a standard logic to many of these problems. Assume you know what subarray with the largest total is nums[:n - 1]. Then what is the subarray with the largest total you can find for the subarray nums[:n]?
There are two possibilities:
The new answer doesn't contain nums[n-1]. In that case, it has to be the same answer as the old answer
The new answer does contain nums[n-1].
So. . .
The actual algorithm is that you iteratively go through the array, repeatedly adding a new element to the array, and keeping track of two answers:
What is the subarray with the largest total
What is the subarray with the largest total containing the last element.
(This answer may be the same as the previous.)
When you then add a new element to the end of the array:
The subarray with the largest total is either (a) the previous largest total or (b) the previous largest total containing the last element plus the new last element or (c) just the last element. Pick the one with the largest total.
The subarray with the largest total containing the last element is the larger of (b) or (c) above.
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
for i in range(1, len(nums)):
if nums[i-1] > 0:
nums[i] += nums[i-1]
return max(nums)
This is a 2 pass O(n) time complexity solution with constant space.
How it works:
We add each element to its predecessor, provided the predecessor is greater than 0 (greater or equal would also do). The Idea is this: If negative numbers have managed to take it below 0, we discard the prefix and don't care about them anymore. But if some positive value is remaining, we add it since it's better than nothing.
At the end we look for the max value.
To make it one pass, you could just have a best value that at each iteration takes the max. Then you wouldn't need to loop over the array at the end again to take the max.
This is by the way Kadane's algorithm, if you are interested to further read about it.
You can use the Kadane's algorithm to solve this problem in O(n) time and space (and constant extra space). It is a simple dynamic programming algorithm:
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
max_sum = -10**4
current_sum = 0
for n in nums:
current_sum = n if n > current_sum+n else current_sum+n
if current_sum > max_sum:
max_sum = current_sum
return max_sum
Here's my solution, although it exceeds time limit when the input list has a lot of elements. My idea is to try the sum of every sublist and update the max sum accordingly. There's a faster, but more complex approach by using "divide and conquer" method: https://leetcode.com/problems/maximum-subarray/discuss/1849465/Divide-and-Conquer-Approach-with-Python
My solution (works in 200/209 cases because of Time Limit Exceeded):
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
max_sum = - 10 ** 4
for i in range(len(nums)):
for j in range(i + 1, len(nums) + 1):
s = sum(nums[i:j])
if max_sum < s:
max_sum = s
return max_sum

How to optimize recursive permutation algorithm for all 4x4 "magic squares"

A "magic square" consists of an n x n matrix where the rows, columns, and diagonals all equal a constant. For 4 x 4 magic squares, that constant is 34. I'm attempting to optimize my permutation algorithm, which currently lists all possible 4 x 4 matrices using digits ranging from 1-16, to skip over certain permutations if the current matrix doesn't match the magic square criteria.
I already have the recursive algorithm to permute all combinations. This function takes a length 16 array, which is representative of the square, and prints all possible combinations that fit the "magic" criteria. I'm not sure how to implement a check in the recursive call to optimize it though. For example, I want it so that if the first row of the matrix doesn't sum up to 34, skip that permutation and proceed to the next one (and so on and so forth for the proceeding rows).
def permute(a, lo, hi):
if(lo == hi) and (isMagic(a)):
print(a)
else:
for i in range(lo, hi):
# this is where I imagine the exceptions would be made
a[lo], a[i] = a[i], a[lo]
permute4(a, lo + 1, hi, count, n)
a[lo], a[i] = a[i], a[lo]
When removing the "isMagic" check, which simply prints all combinations, including those that arent "magic", it takes a painfully long time for the function to print the squares. I ultimately would like to speed this up by excluding unnecessary permutations. How would I implement this check?
The trick is to depend on already generated cells. For example you never need to generate a 4-element permutation, because you know that their sum is 34, thus the 4th element even in the first row has to be 34-sum(first 3 elements). If such element never existed (like 1,2,3,28), or is already in use (like 1,3,15,15), that attempt will not work and you can proceed to the next one without generating the rest of the table. In fact the first two element can already create an upper/lower limit for the remaining ones, for example 1,2 means that the remaining two elements will be 15 and 16. One may pre-generate/filter all the individual permutations having the sum of 34, and pick candidates based on what is already there in the square.
Another trick is connected to this one: if you always generate rows, you always try a lot of things, 3+1 brand new elements. However if you generate a column after having a row in place, you are dealing with a 2-element permutation only (because the first element is known and the last one is calculated).
Example implementation (without pre-generation):
import itertools,time
def check(attempt):
for i in range(0,4):
if sum(attempt[i*4:i*4+4]) != 34:
return False
if sum(attempt[i+j*4] for j in range(0,4)) != 34:
return False
if sum(attempt[i+i*4] for i in range(0,4)) != 34:
return False
if sum(attempt[3-i+i*4] for i in range(0,4)) != 34:
return False
return True
def row(pos,field,rest):
base=34-sum(field[pos*4:pos*4+pos])
for p in itertools.permutations(rest,3-pos):
r=base-sum(p)
s=rest-set(p)
if r in s:
for i in range(pos,3):
field[pos*4+i]=p[i-pos]
field[pos*4+3]=r
column(pos,field,s-{r})
count = 0
def column(pos,field,rest):
if len(rest) == 0:
if check(field):
global count
count+=1
print("{} {}".format(count,field))
return
base=34-sum([field[pos+4*i] for i in range(0,pos+1)])
for p in itertools.permutations(rest,2-pos):
r=base-sum(p)
s=rest-set(p)
if r in s:
for i in range(pos+1,3):
field[pos+i*4]=p[i-pos-1]
field[pos+4*3]=r
row(pos+1,field,s-{r})
start=time.time()
row(0,[0]*16,set(range(1,17)))
print(time.time()-start)
It generates the 7040 solutions in 1-2 minutes (61 seconds on my machine, but it is a relatively new one). It is probably correct, as 880 unique solutions are expected, but this code generates the rotated and mirrored squares too (7040=8*880).
Actually the implementation of check() is overly cautious: because of the generation method it is enough to check the diagonals (the for loop with the two if-s can be removed).

Finding the number of elements in an array to be replaced by a given number such that the sum of the array is smaller than another given number

I need help with a certain problem.Suppose you are given a sorted array "A", which has "N" elements and two integers "X" and "Y". Now you are asked two find the number of elements in "A" you have to replace with "X" such that the sum of the array "A" is less than "Y". The given problem can be easily solved in O(n^2) using the following technique.(Only the code snippet for this is specific operation).
sum = None
count = None
for i in range(N):
for j in range(i):
A[j] = X
count += 1
for k in range(N):
sum += A[k]
if sum==Y:
print(count)
count = 0
break
But I want to do this in a more efficient way,can someone suggest a more efficient way?
Thanks In Advance
Since your array is sorted you can:
calculate the sum of your array (O(n))
check if saved_sum<=Y is satisfied (O(1))
Start at the last/first position (depending on where the largest value is)
3.1 check if that value is larger than X, if not it's not possible to reduce the sum of A any further
3.2 replace by X and decrease saved_sum by value-x
3.3 check if saved_sum <= Y, if not repeat at 3.1 with 2nd largest value in A
Whole thing runs in O(n) since A is sorted and largest/next largest can be found in O(1)

max sum of list elements each separated by (at least) k elements

given a list of numbers to find the maximum sum of non-adjacent elements with time complexity o(n) and space complexity of o(1), i could use this :
sum1= 0
sum2= list[0]
for i in range(1, len(list)):
num= sum1
sum1= sum2+ list[i]
sum2= max(num, sum2)
print(max(sum2, sum1))
this code will work only if the k = 1 [ only one element between the summing numbers] how could improve it by changing k value using dynamic programming. where k is the number of elements between the summing numbers.
for example:
list = [5,6,4,1,2] k=1
answer = 11 # 5+4+2
list = [5,6,4,1,2] k=2
answer = 8 # 6+2
list = [5,3,4,10,2] k=1
answer = 15 # 5+10
It's possible to solve this with space O(k) and time O(nk). if k is a constant, this fits the requirements in your question.
The algorithm loops from position k + 1 to n. (If the array is shorter than that, it can obviously be solved in O(k)). At each step, it maintains an array best of length k + 1, such that the jth entry of best is the best solution found so far, such that the last element it used is at least j to the left of the current position.
Initializing best is done by setting, for its entry j, the largest non-negative entry in the array in positions 1, ..., k + 1 - j. So, for example, best[1] is the largest non-negative entry in positions 1, ..., k, and best[k + 1] is 0.
When at position i of the array, element i is used or not. If it is used, the relevant best until now is best[1], so write u = max(best[1] + a[i], best[1]). If element i is not used, then each "at least" part shifts one, so for j = 2, ..., k + 1, best[j] = max(best[j], best[j - 1]). Finally, set best[1] = u.
At the termination of the algorithm, the solution is the largest item in best.
EDIT:
I had misunderstood the question, if you need to have 'atleast' k elements in between then following is an O(n^2) solution.
If the numbers are non-negative, then the DP recurrence relation is:
DP[i] = max (DP[j] + A[i]) For all j st 0 <= j < i - k
= A[i] otherwise.
If there are negative numbers in the array as well, then we can use the idea from Kadane's algorithm:
DP[i] = max (DP[j] + A[i]) For all j st 0 <= j < i - k && DP[j] + A[i] > 0
= max(0,A[i]) otherwise.
Here's a quick implementation of the algorithm described by Ami Tavory (as far as I understand it). It should work for any sequence, though if your list is all negative, the maximum sum will be 0 (the sum of an empty subsequence).
import collections
def max_sum_separated_by_k(iterable, k):
best = collections.deque([0]*(k+1), k+1)
for item in iterable:
best.appendleft(max(item + best[-1], best[0]))
return best[0]
This uses O(k) space and O(N) time. All of the deque operations, including appending a value to one end (and implicitly removing one from the other end so the length limit is maintained) and reading from the ends, are O(1).
If you want the algorithm to return the maximum subsequence (rather than only its sum), you can change the initialization of the deque to start with empty lists rather than 0, and then append max([item] + best[-1], best[0], key=sum) in the body of the loop. That will be quite a bit less efficient though, since it adds O(N) operations all over the place.
Not sure for the complexity but coding efficiency landed me with
max([sum(l[i::j]) for j in range(k,len(l)) for i in range(len(l))])
(I've replace list variable by l not to step on a keyword).

Fastest algorithm possible to pick number pairs

The question:
Given N integers [N<=10^5], count the total pairs of integers that have a difference of K. [K>0 and K<1e9]. Each of the N integers will be greater than 0 and at least K away from 2^31-1 (Everything can be done with 32 bit integers).
1st line contains N & K (integers).
2nd line contains N numbers of the set. All the N numbers are assured to be distinct.
Now the question is from hackerrank. I got a solution for the question but it doesn't satisfy the time-limit for all the sample test cases. I'm not sure if its possible to use another algorithm but I'm out of ideas. Will really appreciate if someone took a bit of time to check my code and give a tip or two.
temp = input()
temp = temp.split(" ")
N = int(temp[0])
K = int(temp[1])
num_array = input()
num_array = num_array.split(" ")
diff = 0
pairs= 0
i = 0
while(i < N):
num_array[i] = int(num_array[i])
i += 1
while(num_array != []):
j = 0
while(j < (len(num_array)-1)):
diff = abs(num_array[j+1] - num_array[0])
if(diff == K):
pairs += 1
j += 1
del num_array[0]
if(len(num_array) == 1):
break
print(pairs)
You can do this in aproximately linear time by following the procedure:
So, O(n) solution:
For each number x add it to hash-set H[x]
For each number x check whether x-k is in H, if yes - add 1 to answer
Or by using some balanced structure (like tree-based set) in O(nlgn)
This solution bases on the assumption that integers are distinct, if they are not you need to store the number of times element has been "added to set" and instead of adding 1 to answer - add the product of H[x]*H[x+k]
So in general you take some HashMap H with "default value 0"
For each number x update map: H[x] = H[x]+1
For each number x add to answer H[x]*H[x-k] (you don't have to check whether it is in the map, because if it is not, H[x-k]=0 )
and again - solution using hash-map is O(n) and using tree-map O(nlgn)
So given set of numbesr A, and number k (solution for distinct numbers):
H=set()
ans=0
for a in A:
H.add(a)
for a in A:
if a-k in H:
ans+=1
print ans
or shorter
H=set(A)
ans = sum(1 for a in A if a-k in H)
print ans
Use a dictionary (hash map).
Step 1: Fill the dictionary D with all entries from the array.
Step 2: Count occurences of all A[i] + k in the dictionary.
Dictionary<int> dict = new Dictionary<int>();
foreach (int n in num_array) do dict.Add(n);
int solitions = 0;
foreach (int n in num_Array) do
if dict.contains(n+k)
solutions += 1;
Filling a dictionary is O(1), Searching is O(1) as well. Doing it for each element in the array is O(n). This is as fast as it can get.
Sorry, you have to translate it to python, though.
EDIT: Same idea as the previous one. Sorry to post a duplicate. It's too late to remove my duplicate I guess.

Categories

Resources