Related
We have an unsorted array size of n-1, that has the numbers from 1 to n excluding one number. We need to find that missing number.
Like if we have as input [8,1,5,4,2,7,6], then it should return 3.
Constraints I got:
Try to collect smaller patient numbers to the left and bigger numbers to the right. In your solution, you have to use the Partition algorithm that is used by QuickSort (solutions that do not use partitioning and recursion, such as subtracting the sum of the elements in A from the sum of the integers up-to n will not be a valid answer).
How is this possible?
This problem can be solved with an algorithm that is much like quickselect:
The idea is to partition the input array like with quickselect (and quicksort). At that point we know the pivot element appears where it would be when the array would have been sorted. There are two possibilities:
The value of the pivot is 2 more than the index where it resides. For instance if we have [1, 3, 4] and the middle element is the pivot, then indeed the value 3 is two more than the index (1) where it resides.
In this case we can conclude that the missing value is less than the pivot value, and we could repeat the process recursively in the left partition
The value of the pivot is 1 more than the index where it resides. For instance if we have [1, 2, 4] and the middle element is the pivot, then indeed the value 2 is one more than the index (1) where it resides.
In this case we can conclude that the missing value is greater than the pivot value, and we could repeat the process recursively in the right partition
Here is an implementation of that algorithm in Python code:
from random import randint
def partition(arr, l, r):
i = randint(l, r) # choose pivot randomly
arr[i], arr[r] = arr[r], arr[i] # swap it out of the way
x = arr[r] # get pivot value
i = l
for j in range(l, r):
if arr[j] <= x:
arr[i], arr[j] = arr[j], arr[i] # swap
i += 1
# swap pivot element into its final place
arr[i], arr[r] = arr[r], arr[i]
return i
def findmissing(arr, l, r):
if l > r: # base case
return arr[r] + 1 if r >= 0 else 1
pivotindex = partition(arr, l, r)
if arr[pivotindex] == pivotindex + 2: # missing element must be on the left
return findmissing(arr, l, pivotindex - 1)
else: # missing element is on the right
return findmissing(arr, pivotindex + 1, r)
# Demo run
arr = [8,1,5,4,2,7,6]
print(findmissing(arr, 0, len(arr)-1)) # 3
Is there an efficient algorithm to generate a permutation from one index provided? The permutations do not need to have any specific ordering and it just needs to return every permutation once per every possible index. The set I wish to permute is all integers from 0~255.
If I understand the question correctly, the problem is as follows: You are given two integers n and k, and you want to find the kth permutation of n integers. You don't care about it being the kth lexicographical permutation, but it's just easier to be lexicographical so let's stick with that.
This is not too bad to compute. The base permutation is 1,2,3,4...n. This is the k=0 case. Consider what happens if you were to swap the 1 and 2: by moving the 1, you are passing up every single permutation where 1 goes first, and there are (n-1)! of those (since you could have permuted 2,3,4..n if you fixed the 1 in place). Thus, the algorithm is as follows:
for i from 1 to n:
j = k / (n-i)! // integer division, so rounded down
k -= j * (n-i)!
place down the jth unplaced number
This will iteratively produce the kth lexicographical permutation, since it repeatedly solves a sub-problem with a smaller set of numbers to place, and decrementing k along the way.
There is an implementation in python in module more-itertools: nth_permutation.
Here is an implementation, adapted from the code of more_itertools.nth_permutation:
from sympy import factorial
def nth_permutation(iterable, index):
pool = list(iterable)
n = len(pool)
c = factorial(n)
index = index % c
result = [0] * n
q = index
for d in range(1, n + 1):
q, i = divmod(q, d)
if 0 <= n - d < n:
result[n - d] = i
if q == 0:
break
return tuple(map(pool.pop, result))
print( nth_permutation(range(6), 360) )
# (3, 0, 1, 2, 4, 5)
Given an array A, you can repeatedly delete any contiguous subarrays with length k that sum to tar from it. Output whether A can be made empty through this process.
A is an integer array, k is a positive integer, tar is an integer.
For example, A=[1,2,3,4];k=2;tar=5
Then you can delete [2,3] from A so that it becomes [1,4]. Then you delete [1,4] from A; it becomes empty. Therefore, the algorithm should output True.
Currently I have found a O(n^2/k*comb(n/k,k)) algorithm. Is there a better one?
My algorithm
Firstly, use dp, find whether A[i:j] can be empty, then enumerate all elements of the last deleted subarray, in time O(comb((j-i)/k, k)),
An example code of python3, when k is 3:
from functools import lru_cache
from itertools import accumulate
def solve(A, k, tar):
# only works when k = 3
assert k==3
presum = list(accumulate(A, initial=0))
#lru_cache(None)
def judge(i, j):
"""
find if s[i:j] can be full erased
"""
l,remainder = divmod(j-i,k)
if remainder != 0 or presum[j]-presum[i] != tar*l:
return False
if l<=1:
return True
# enumerate the last 3 elements to be erased
# # find triplets that sum to tar
for a1 in range(i, j, 3):
for a2 in range(a1+1, j, 3):
for a3 in range(a2+1, j, 3):
if A[a1]+A[a2]+A[a3]==tar:
prv = i
flag = True
for nxt in a1,a2,a3,j:
if not judge(prv, nxt):
flag = False
break
prv = nxt+1
if flag == True:
return True
return False
return judge(0,len(A))
print(solve([1,2,3,4,8,0],3,9))
additional problem
I also wonder if there is any specific algorithm when k is 3 and 2.
A testcase that when k=3 greedy doesn't work:
A=[5,5,5,1,9,7,3,0,10, 5,5,5, 10,0,3,7,9,1,5,5,5];tar=15;k=3
For problems where we're dealing with a sequence of operations, you can often get a dynamic programming solution by parameterizing on the first or last operation you will perform.
For our array A = [a_0, a_1, ... a_{n-1}], let's guess what the last move will be. It must be to remove k elements summing to our target, and those elements [x_0, x_1, ... x_{k-1}] form a subsequence of A which partitions the other elements of A into at most k+1 other subarrays. Before performing the last operation, the other subarrays have already been completely and individually deleted by some operations, and the subproblem on each of those subarrays is completely analogous to our original problem. This an example of optimal substructure.
Now that the framework is set up, let's talk about details. There's lots of easy edge cases: if k is 1, or if the length of the array isn't divisible by k, or if the sum of the array is incorrect, that we should check first. I'll also be assuming that target and the entries of A are nonnegative, but this can be modified with small additions to the code without affecting the runtime complexity.
What variables do our subproblems need to keep track of? There's the left and right bounds of our current array, as well as the number and sum of all the outer partition elements we've already taken. We don't know yet which k partition elements will be in the last operation-- they could be spread out over the entire original array.
We'll be walking through the array from left to right, at each point testing whether we can use the current element for that outer partition, or whether to process the next k, or 2k, or 3k, ... elements together as a contiguous subarray and continue on after that. We can filter out most subarrays from consideration: a subarray S is potentially solvable if its length is some multiple of k, m*k, and its sum is m*target. We can use prefix sums to test this quickly.
Python
def solve(arr: List[int], k: int, target: int) -> bool:
"""Decide whether arr is completely removable
Given an array of nonnegative integers arr, a positive integer length k,
and a nonnegative target sum, decide whether we can remove all elements
of arr by repeatedly removing k consecutive elements summing to target.
"""
assert k > 0
assert target >= 0
# This section deals with any easy edge cases
if len(arr) % k != 0:
return False
if k == 1:
return all(x == target for x in arr)
prefixes = list(itertools.accumulate(arr, initial=0))
if target == 0: # Assumes target >= 0 and all values >= 0
return prefixes[-1] == 0
if prefixes[-1] != target * (len(arr) // k):
return False
if k == len(arr):
return True
reverse_index = collections.defaultdict(list)
starts_to_ends = collections.defaultdict(list) # Candidate subarrays
for right, x in enumerate(prefixes):
remainder = x % target
for left in reverse_index[remainder]:
if (right - left) % k == 0:
if (right - left) // k == (x - prefixes[left]) // target: # Valid sum
starts_to_ends[left].append(right-1)
reverse_index[remainder].append(right)
#functools.lru_cache(None)
def can_solve(left: int, right, outer_need: int, outer_sum_need: int) -> bool:
elements_remaining = right - left + 1
# We've reached the end of our array
if elements_remaining == 0:
return outer_need == outer_sum_need == 0
# All elements must go to the outer partition
if elements_remaining == outer_need:
return prefixes[right + 1] - prefixes[left] == outer_sum_need
# We've used k elements for the outer partition, but
# their sum is too small
if outer_need == 0 and outer_sum_need != 0:
return False
# Test whether we can split into two subproblems
for poss_ending in starts_to_ends[left]:
if poss_ending >= right:
break
if (can_solve(left, poss_ending, 0, 0)
and can_solve(poss_ending + 1, right, outer_need, outer_sum_need)):
return True
# We are just starting a subproblem: Initialize outer partition as empty
# and try using current element in outer partition
if outer_need == 0 and outer_sum_need == 0:
if (arr[left] <= target
and can_solve(left + 1, right, k - 1, target - arr[left])):
return True
# Try using current element in outer partition
if outer_need > 0 and arr[left] <= outer_sum_need:
if can_solve(left + 1, right, outer_need - 1, outer_sum_need - arr[left]):
return True
return False
return can_solve(left=0, right=len(arr) - 1, outer_need=0, outer_sum_need=0)
This can be modified to actually output the arrays to delete in order, with some more work. The current runtime is O(n^2 * target * n/k) (saving a factor of k because of our pre-filtering trick when the sum or length of an array is wrong). For many solvable arrays, a 'greedy' strategy will work and be much faster, so an optimization could be to try that first.
I believe (and have some empirical evidence) that the runtime can be brought down to O(n^2 * target), by eliminating the loop inside of the recursive function. Instead of testing all 'chunks' of the next k, or 2k, or 3k elements as a separate subproblem, it appears that you only need to test the largest such chunk whose sum is valid, although I haven't found a satisfactory proof that this always gives the right answer.
To expand on my comment: k = 2 can be handled by a linear-time greedy algorithm (push each element of A on a stack, popping the top two elements whenever they exist and sum to tar).
What makes k = 2 different is that if A contains x, y, z with x + y = tar and y + z = tar, then x = z and it doesn't matter which one we remove with y.
More formally, we show by induction on the length of A that no removal causes us to lose the ability to empty the array. This is obvious when A is empty. Inductively, suppose that all arrays shorter than A that can be emptied, can be emptied by any maximal sequence of valid removals. If A can't be emptied, then there's nothing to lose. Otherwise, we can remove some pair p and proceed to empty A. Suppose that we remove some other pair q instead. There are two cases.
p and q overlap. As we argued above, the resulting array will be the same, and by assumption we can empty it.
p and q do not overlap. Then we can get the same array by removing p then q, or q then p. By assumption and the inductive hypothesis, the former order must allow us to empty the resulting array, so the latter order is also fine.
Given a list of values (e.g. 10, 15, 20, 30, 70), values N (e.g. 3) and S (e.g. 100), find a subset that satisfies :
length of subset >= N
sum of subset >= S
The sum of the subset should also be the least possible (the sum of remaining values should be the greatest possible) (e.g. result subset should be (10,20,70), not (15,20,70) which also satisfies 1. and 2.).
I was looking at some problems and solutions (Knapsack problem, Bin packing problem, ...) but didn't find them applicable. Similar problems on the internet were also not suitable for some reason (e.g. number of elements in subset was fixed).
Can someone point me in the right direction? Is there any other solution other than exhausting every possible combination?
Edit - working algorithm I implemented in ruby code, I guess it can be further optimized:
def find_subset_with_sum_and_length_threshold(vals, min_nr, min_sum)
sum_map = {}
vals.sort.each do |v|
sum_map.keys.sort.each do |k|
addends = sum_map[k] + [v]
if (addends.length >= min_nr && k+v >= min_sum)
return addends
else
sum_map[k+v] = addends
end
end
sum_map[v] = [v] if sum_map[v].nil?
end
end
This is not very different from the 0-1 knapsack problem.
Zero-initialize a matrix with S+U rows and N columns(U is the largest list value)
Zero-initialize a bit array A with S+U elements
For each value (v) in the list:
For each j<S:
If M[N-1,j] != 0 and M[N-1, j + v] == 0:
M[N-1, j + v] = v
A[j + v] = true
For i=N-2 .. 0:
For each j<S:
If M[i,j] != 0 and M[i+1, j + v] == 0:
M[i+1, j + v] = v
M[0,v] = v
Find first nonzero element in M[N-1,S..S+U]
Reconstruct other elements of the subset by subtracting found value from its\
index and using the result as index in preceding column of the matrix\
(or in the last column, depending on the corresponding bit in 'A').
Time complexity is O(L*N*S), where L is the length of the list, N and S are given limits.
Space complexity is O(L*N).
Zero-initialize an integer array A with S+U elements
i=0
For each value (v) in the list:
For each j<S:
If A[j] != 0 and A[j + v] < A[j] + 1:
A[j + v] = A[j] + 1
V[i,j + v] = v
P[i,j + v] = I[j]
I[j + v] = i
If A[v] == 0:
A[v] = 1
I[v] = i
++i
Find first element in A[S..S+U] with value not less than N
Reconstruct elements of the subset using matrices V and P.
Time complexity is O(L*S), where L is the length of the list, S is given limit.
Space complexity is O(L*S).
Algorithm that also minimizes the subset size:
Zero-initialize a boolean matrix with S+U rows and N columns\
(U is the largest list value)
Zero-initialize an integer array A with S+U elements
i=0
For each value (v) in the list:
For each j<S:
If A[j] != 0 and (A[j + v] == 0) || (A[j + v] > A[j] + 1)):
A[j + v] = A[j] + 1
V[i,N-1,j + v] = v
P[i,N-1,j + v] = (I[j,N-1],N-1)
I[j+v,N-1] = i
For k=N-2 .. 0:
For each j<S:
If M[k,j] and not M[k+1, j + v]:
M[k+1, j + v] = true
V[i,k+1,j + v] = v
P[i,k+1,j + v] = (I[j,k],k)
I[j+v,k+1] = i
For each j<S:
If M[N-1, j]:
A[j] = N-1
M[0,v] = true
I[v,0] = i
++i
Find first nonzero element in A[N-1,S..S+U] (or the first element with smallest\
value or any other element that suits both minimization criteria)
Reconstruct elements of the subset using matrices V and P.
Time complexity is O(L*N*S), where L is the length of the list, N and S are given limits.
Space complexity is O(L*N*S).
This is a slight variation of Subset sum problem. Look at section Pseudo-polynomial time dynamic programming solution. In addition to keeping track whether a particular sum is possible (i.e. storing true/false) from the given set, you would need to store the length too to satisfy:
length of subset >= N
if sum of subset = S then it is exactly similar to the above problem. For sum of subset >= S condition, I guess you can test this condition when building the array as mentioned in the Wiki page.
Given two arrays, how to find the maximum element which is common to both the arrays?
I was thinking of sorting both the arrays(n log n) and then perform the binary search of every element from one sorted array(starting from larger one) in another array until match is found.
eg:
a = [1,2,5,4,3]
b = [9,8,3]
Maximum common element in these array is 3
Can we do better than n log n?
With some extra space you could hash in 1 array, then do a contains on each element of the other array keeping track of the biggest value that returns true. Would be O(n).
You can but using O(N) space.
Just go through the first array and place all elements in a HashTable. This is O(N)
Then go through the second array keeping track of the current maximum and checking if the element is in the HashTable. This is also O(N) .
So total runtime is O(N) and O(N) extra space for the HashTable
Example in Java:
public static int getMaxCommon(int[] a, int[] b){
Set<Integer> firstArray = new HashSet<Integer>(Arrays.asList(a));
int currentMax = Integer.MIN_VALUE;
for(Integer n:b){
if(firstArray.contains(n)){
if(currentMax < n){
currentMax = n
}
}
}
return currentMax;
}
While it depends on the time complexities of the various operations in specific languages, how about creating sets from the arrays and finding the maximum value in the intersection of the two sets? Going by the time complexities for operations in Python, it'd be, on average, O(n) for the set assignments, O(n) for the intersections, and O(n) for finding the max value. So average case would be O(n).
However! Worst-case would be O(len(a) * len(b)) -> O(n^2), because of the worst-case time complexity of set intersections.
More info here, if you're interested: http://wiki.python.org/moin/TimeComplexity
If you already know the range of numbers that would be in your arrays, you could perform counting sort, and then perform the binary search like you wanted. This would yield O(n) runtime.
Pseudocode:
sort list1 in descending order
sort list2 in descending order
item *p1 = list1
item *p2 = list2
while ((*p1 != *p2) && (haven't hit the end of either list))
if (*p1 > *p2)
++p1;
else
++p2;
// here, either we have *p1 == *p2, or we hit the end of one of the lists
if (*p1 == *p2)
return *p1;
return NOT_FOUND;
Not a perfect, but a simple solution, O(len(array1) + len(array2))
import sys
def find_max_in_common(array1, array2):
array1 = set(array1)
array2 = set(array2)
item_lookup = {}
for item in array1:
item_lookup[item] = True
max_item = -sys.maxsize
intersection = False
for item in array2:
if not item_lookup.get(item, None):
continue
else:
intersection = True
if item > max_item:
max_item = item
return None if not intersection else max_item
Solution using binary search (and invariants to "proof" correctness):
from bisect import bisect_left
def findLargestCommon(nums0, nums1):
# Find the largest common element of two sorted lists
if not nums0 or not nums1:
return None
i = len(nums0) - 1
j = len(nums1) - 1
if nums0[i] == nums1[j]:
return nums0[i]
elif nums0[i] > nums1[j]:
nums0, nums1 = nums1, nums0
i, j = j, i
while i >= 0 and j > 0:
# nums0[i] < nums1[j]
# look for nums0[i] in nums1[:j]
jj = bisect_left(nums1, nums0[i], hi=j)
if jj == j:
# nums1[j-1] < nums0[i] < nums1[j]
j -= 1
# nums1[j] < nums0[i]
nums0, nums1 = nums1, nums0
i, j = j, i
# nums0[i] < nums1[j]
# (jj != j) and nums1[jj] >= nums0[i]
elif nums1[jj] == nums0[i]:
return nums0[i]
else: # nums1[jj] > nums0[i]
j = jj
# nums0[i] < nums1[j]
return None