Given an array A, find a shortest subarray A[i : j ] such that each distinct value present in A is also present in the subarray.
The question is not for a homework. It's a practice problem from a chapter on Hash tables. I am not looking for the code. Just looking for the algorithm or hints.
1- Maintain a hash table element->count
2- Traverse array from begin to end, incrementing the element count. Whenever an element count is changed from 0 to 1, record it's index in a variable , say index_0_1. In the end index_0_1 will have end index of a potential ans.
3- Traverse array from begin to index_0_1, decrementing the element count. Stop, whenever an element count is changed from 1 to 0, record it's index in a variable, say index_1_0. subarray A[index_1_0 : index_0_1] is a potential ans, record it.
4- Traverse from index_0_1 towards end, incrementing the element count and stop whenever you find element A[index_1_0]. Update index_0_1 with current index.
5- Traverse from index_1_0+1 to index_0_1, decrementing the element count. Stop whenever an element count is changed from 1 to 0. This is new index_1_0. If subarray A[index_1_0: index_0_1] is smaller than previous ans, update it and continue with steps 4 and step 5, until whole array have been traversed.
Use a hash table to maintain a count of each type of element in the string.
when you find a new type of element
discard all previous answers and start trimming the start of the substring,
when you can trim it no more without having zero of one type of element
remember the substring if it's the shortest yet found and then start looking for another element to replace the one you are about to loose or to find a new element not previously seen as above.
When you hit the end of the string you are done.
If your hash is any good, this should be O(n)
Related
I'm looking for a solution for this problem.
I have an array which defines the rule of the order of elements like below.
let rule = [A,B,C,D,E,F,G,H,I,J,K]
I then have another array whose element can be removed or added back.
So for example, I have a list like this:
var list = [A,D,E,I,J,K]
Now If I want to add element 'B' to 'list' the list should be
var list = [A,B,D,E,I,J,K]
because 'B' comes after 'A' and before 'D' in the rule array. So the insertion index would be 1 in this case.
The item in the array are not comparable each other (Let's say a developer can change the order of rule list at any time if that make sense). And there needs no duplicates in the array.
I'm not sure if I explained the problem clearly, but I'd like to know a good approach that finds an insertion index.
Explained the Python code in comments. Basically, find the right place to insert the new element using binary search. The order of elements is decided using rank. The below code assumes that if elements is non-empty then the rule is followed by items in the elements.
rule = ['A','B','C','D','E','F','G','H','I','J','K']
rank = dict()
for i in range(len(rule)):
rank[rule[i]] = i
elements = ['A','D','E','I','J','K'] #list in which we wish to add elements
target = 'B' #element to be inserted
#Binary search to find the right place to insert the target in elements
left, right = 0, len(elements)
while left < right:
mid = left + (right - left) // 2
if rank[elements[mid]] >= rank[target]:
right = mid
else:
left = mid + 1
elements.insert(left, target) #left is the insertion index
print(elements)
Time complexity of add: O(log(len(elements)))
Space complexity: O(1)
If the items are unique (only can occur once), and are not comparable to each other (don't know that B comes after A), then.
Iterate through the rules and find the items position in the rule array.
Check if it is the first item in rules, if so insert at the first position and skip the other steps.
Check to see if it is the last item in rules, if so insert at the end and skip the other steps.
Select the value of the item 1 before into a variable A.
Select the value of the item 1 after into a variable B.
Iterate through the list,
if you encounter the value in parameter A insert it after that value, if you encounter the value B, add the value before that.
If you come to the end without finding either value A or B, then you need to repeat but with values 2 before and 2 after the item in the rules (again checking to see if you hit the start or end of the rules list).
You will probably want to make 6 & 7 a function that calls itself recursively.
A simple approach is, we can use one iteration of Insertion sort.
So, we start from right side of array compare our input x with array elements a go from right to left side. if we arrive an index i of array that let[i]<=x then let[i+1] is correct location that x can be insert.
This approach that has time complexity O(n), follow from correctness of Insertion sort.
Note that the lower of your problem is O(n) because your data structure is array so you need after each insertion shift whole elements.
In steven skiena's the algorithm design manual (page 85),
The author show in a table that priority queue implemented in unsorted array only take O(1) for both insertion and find minimum operation.
For my understanding unsorted array wasn't able get the minimum item in O(1) , because it has to search through the whole array to get the minimum.
is there any details i missed out in priority queue ?
It's (mostly) written there under the table:
The trick is using an extra variable to store a pointer/index to the minimum ...
Presumably, the next word is "value", meaning it's a simple O(1) dereference to get the minimum.
When inserting an item, you just append it to the end and, if it's less than the current minimum, update that pointer/index. That means O(1) for the insert.
The only "expensive" operation is then delete-minimum. You know where it is due to the pointer/index but it will take O(n) operations to shuffle the array elements beyond it down one.
And, since the cost is already O(n), you may as well take the opportunity to search the array for the new minimum and store its position in the pointer/index.
The pseudo-code for those operations be something along the lines of (first up, initialisation and insertion, and assuming zero-based indexes):
class prioQ:
array = [] # Empty queue.
lowIndex = 0 # Index of lowest value (for non-empty queue).
def insert(item):
# Add to end, quick calc if array empty beforehand.
array.append(item)
if len(array) == 1:
lowIndex = 0
return
# Adjust low-index only if inserted value smaller than current.
if array[lowIndex] > item:
lowIndex = len(array) - 1
Then a function to find the actual minimum value:
def findMin():
# Empty array means no minimum. Otherwise, return minimum.
if len(array) == 0: return None
return array[lowIndex]
And, finally, to extract the minimum value (remove it from the queue and return it):
def extractMin():
# Empty array means no minimum. Otherwise save lowest value.
if len(array) == 0: return None
retVal = array[lowIndex]
# Shuffle down all following elements to delete lowest one
for index = lowIndex to len(array) - 2 inclusive:
array[index] = array[index + 1]
# Remove final element (it's already been shuffled).
delete array[len(array) - 1]
# Find lowest element and store.
if len(array) > 0:
lowIndex = len(array) - 1
for index = len(array) - 2 to 0 inclusive:
if array[index] <= array[lowIndex]:
lowIndex = index
# Return saved value.
return retVal
As an aside, the two loops in the extractMin function could be combined in to one for efficiency. I've left it as two separate loops for readability.
One thing you should keep in mind, there are actually variations of the priority queue that preserve insertion order (within a priority level) and variations that do not care about that order.
For the latter case, you don't have to shuffle all the elements to remove an extracted one, you can simply move the last one in the array over the extracted one. This may result in some time savings if you don't actually need to preserve insertion order - you still have to scan the entire array looking for the new highest-priority item but at least the number of shuffle assignments will be reduced.
#paxdiablo's answer gives the scheme referred to in the book. Another way to achieve the same complexity is to always store the minimum at the first index in the array:
To insert x in O(1) time, either insert it at the end (if it is bigger than the current minimum), or copy the current minimum to the end and then store x at index 0.
To query the minimum in O(1) time, return the value at index 0.
To delete the minimum in O(n) time, search for the new minimum from index 1 onwards, write it at index 0, then "fill in the gap" by swapping the element at the last index to where the new minimum used to be.
A standard problem in many languages is to sort an array and sort the indices as well. So for instance, if a = {4,1,3,2} the sorted array is b = {1,2,3,4} and the original indices moved would be {1,3,2,0}. This is easy to do by sorting a vector of pairs for instance.
What I want instead is an array c so that c[i] is the new position of element a[i] in the array b. So, in my example, c = {3,0,2,1} because 4 moves to position 3, 1 moved to position 0 and so on.
One way is to look up each element a[i] in b (perhaps using binary search to reduce lookup time) and then add the corresponding index in c. Is there a more efficient way?
Can you assume that you have the array of originally indices moved? It's the only array above that you didn't assign to a variable. If so, one efficient way of solving this problem is to back calculate it from that array of original indices moved.
You have that as {1,3,2,0}. All you need to do it march through it and put each values index at the value indicated.
So index 0 has a 1. That means at index 1 of the new array there should be a zero. Index 1 is a 3, so at index 3 of the new array put a 1. You would get your goal of {3,0,2,1}
Can you find whether two-time interval arrays are overlapping or not, in an optimized way?
Suppose input array A contains 10 elements, and each and every element have a start date and end date, And similarly, input array B contains 4 elements, and each and every element have a start data and end data. Now find whether A and B are overlapping or not?
Example 1:
Input:
A={[1,5],[7,10],[11,15]}; //Array A contains 3elements, and each element have start and end time.
B={[6,10],[1,5]};//Array B contains 2elements, and each element have start and end time.
Output: Yes // why because A and B are overlapping at [6,10] || [1,5]
Example 2:
Input:
A={[1,5],[8,10],[11,15]}; //Array A contains 3elements, and each element have start and end time.
B={[5,8],[15,16]};//Array B contains 2elements, and each element have start and end time.
Output: No // why because A and B are not-overlapping at [5,8] || [15,16]
I know we can solve this problem by using brute force, by iterating each element
in B and comparing with each element of A to check whether overlapping or not(A[i].start<=B[j].start and A[i].end>B[j].start), it'll take O(N*M) where N is length of array A and M is length of B.
Can you please optimize the solution.
You can sort the array according to the start times. You can then check if the end time of an element is greater than the start time of next element by iterating through both the arrays simultaneously(use two pointers). If it is the case, then you have found an overlap.
Here is what you can do
Build a segment tree using the values of array A. if the first interval id (l1, r1), 2nd is (l2, r2) and so on.
for every interval in A(li, ri) update the segment tree such that we update each element in the interval (li, ri) to 1. this can be done in O(logn) using lazy propagation
now for each interval in B(lj, rj) try to query the segment tree for this range. a query would return the sum of the range (lj, rj)
if sum is 0, then that range is non overlapping. else it is overlapping
overall complexity O(nlogn)
Suppose you are given an unsorted list of positive integers, and you wish to order them in a manner such that the elements alternate as: (less than preceding element), (greater than preceding element), (less than preceding element), etc... The very first element in the output list may ignore the rule. So for example, suppose your list was: 1,4,9,2,7,5,3,8,6.
One correct output would be...
1,9,2,8,3,7,4,6,5
Another would be...
3,4,2,7,5,6,1,9,8
Assume that the list contains no duplicates, is arbitrarily large, and is not already sorted.
What is the most processing efficient algorithm to achieve this?
Now, the standard approach would be to simply sort the list in ascending order first, and then peel elements from the ends of the list in alternation. However, I'd like to know: Is there a more time-efficient way to do this without first sorting the list?
My reason for asking: (read this only if you care)
Apparently this is a question my sister's boyfriend poses to people at job interviews out in San Francisco. My sister asked me the question, and I immediately came up with the standard response. That's what everyone answers. However, apparently one girl came up with a completely different solution that does not require sorting the list, and it appears to work. My sister couldn't explain to me this solution, but the idea has been confounding me since last night. I'd appreciate any help! Thanks!
You can do this in O(n) by placing each element in turn at the end, or at the penultimate position based on a comparison with the current last element.
For example,
1,4,9,2,7,5,3,8,6
Place 1 at end, current list [1]
4>1 true so place 4 at end, current list [1,4]
9<4 false so place 9 at penultimate position [1,9,4]
2>4 false so place 2 at penultimate [1,9,2,4]
7<4 false so place 7 at penultimate [1,9,2,7,4]
5>4 true so place 5 at end [1,9,2,7,4,5]
3<5 true so place 3 at end [1,9,2,7,4,5,3]
8>3 true so place 8 at end [1,9,2,7,4,5,3,8]
6<8 true so place 6 at end [1,9,2,7,4,5,3,8,6]
Note that the equality tests alternate, and that we place at the end if the equality is true, or at the penultimate position if it is not true.
Example Python Code
A=[1,4,9,2,7,5,3,8,6]
B=[]
for i,a in enumerate(A):
if i==0 or (i&1 and a>B[-1]) or (i&1==0 and a<B[-1]):
B.insert(i,a)
else:
B.insert(i-1,a)
print B
One solution is this. Given in Pseudocode.
Assuming, nums has at least two elements and all elements in nums are distinct.
nums = [list of numbers]
if nums[0] < nums[1]: last_state = INCREASING else: last_state = DECREASING
for i = 2 to len(nums - 1):
if last_state = INCREASING:
if nums[i] > nums[i-1]:
swap (nums[i], nums[i-1])
last_state = DECREASING
else
if nums[i] < nums[i-1]:
swap (nums[i], nums[i-1])
last_state = INCREASING
Proof of correctness:
After each loop iteration, elements upto index i in nums remain alternating and last_state is represent the order of i th and i-1 th elements.
Note that a swapping happens only if last 3 items considered are in order. (Increasing or Decreasing) Therefore, if we swapped ith element with i-1 th element, the order of i-2 th element and i-1th element will not change.