LeetCode 1707. Maximum XOR With an Element From Array - algorithm

You are given an array nums consisting of non-negative integers. You are also given a queries array, where queries[i] = [xi, mi].
The answer to the ith query is the maximum bitwise XOR value of xi and any element of nums that does not exceed mi. In other words, the answer is max(nums[j] XOR xi) for all j such that nums[j] <= mi. If all elements in nums are larger than mi, then the answer is -1.
Return an integer array answer where answer.length == queries.length and answer[i] is the answer to the ith query.
This python solution uses Trie, but still LeetCode shows TLE?
import operator
class TrieNode:
def __init__(self):
self.left=None
self.right=None
class Solution:
def insert(self,head,x):
curr=head
for i in range(31,-1,-1):
val = (x>>i) & 1
if val==0:
if not curr.left:
curr.left=TrieNode()
curr=curr.left
else:
curr=curr.left
else:
if not curr.right:
curr.right=TrieNode()
curr=curr.right
else:
curr=curr.right
def maximizeXor(self, nums: List[int], queries: List[List[int]]) -> List[int]:
res=[-10]*len(queries)
nums.sort()
for i in range(len(queries)):
queries[i].append(i)
queries.sort(key=operator.itemgetter(1))
head=TrieNode()
for li in queries:
max=0
xi,mi,index=li[0],li[1],li[2]
m=2**31
node = head
pos=0
if mi<nums[0]:
res[index]=-1
continue
for i in range(pos,len(nums)):
if mi<nums[i]:
pos=i
break
self.insert(node,nums[i])
node=head
for i in range(31,-1,-1):
val=(xi>>i)&1
if val==0:
if node.right:
max+=m
node=node.right
else:
node=node.left
else:
if node.left:
max+=m
node=node.left
else:
node=node.right
m>>=1
res[index]=max
return -1

here is alternative Trie implement to solve this problem:
[Notes: 1) max(x XOR y for y in A); 2) do the greedy on MSB bit; 3) sort the queries]
class Trie:
def __init__(self):
self.root = {}
def add(self, n):
p = self.root
for bitpos in range(31, -1, -1):
bit = (n >> bitpos) & 1
if bit not in p:
p[bit] = {}
p = p[bit]
def query(self, n):
p = self.root
ret = 0
if not p:
return -1
for bitpos in range(31, -1, -1):
bit = (n >> bitpos) & 1
inverse = 1 - bit
if inverse in p:
p = p[inverse]
ret |= (1 << bitpos)
else:
p = p[bit]
return ret
class Solution:
def maximizeXor(self, nums: List[int], queries: List[List[int]]) -> List[int]:
n = len(nums)
trie = Trie()
q = sorted(enumerate(queries), key = lambda x: x[1][1])
nums.sort()
res = [-1] * len(queries)
i = 0
for index, (x, m) in q:
while i < n and nums[i] <= m:
trie.add(nums[i])
i += 1
res[index] = trie.query(x)
return res

The problem is that you're building a fresh Trie for each query. And to make matters worse, use linear search to find the maximum value <= mi in nums. You'd be better off by simply using
max((n for n in nums if n <= mi), key=lambda n: n^xi, default=-1)
The solution here would be to build the trie right at the start and simply filter for values smaller than mi using that trie:
import math
import bisect
def dump(t, indent=''):
if t is not None:
print(indent, "bit=", t.bit, "val=", t.val, "lower=", t.lower)
dump(t.left, indent + '\tl')
dump(t.right, indent + '\tr')
class Trie:
def __init__(self, bit, val, lower):
self.bit = bit
self.val = val
self.lower = lower
self.left = None
self.right = None
def solve(self, mi, xi):
print('-------------------------------------------')
print(self.bit, "mi(b)=", (mi >> self.bit) & 1, "xi(b)=", (xi >> self.bit) & 1, "mi=", mi, "xi=", xi)
dump(self)
if self.val is not None:
# reached a leave of the trie => found matching value
print("Leaf")
return self.val
if mi & (1 << self.bit) == 0:
# the maximum has a zero-bit at this position => all values in the right subtree are > mi
print("Left forced by max")
return -1 if self.left is None else self.left.solve(mi, xi)
# pick based on xor-value if possible
if (xi >> self.bit) & 1 == 0 and self.right is not None and (mi > self.right.lower or mi == ~0):
print("Right preferred by xi")
return self.right.solve(mi, xi)
elif (xi >> self.bit) & 1 == 1 and self.left is not None:
print("Left preferred by xi")
return self.left.solve(~0, xi)
# pick whichever is available
if self.right is not None and (mi > self.right.lower or mi == ~0):
print("Only right available")
return self.right.solve(mi, xi)
elif self.left is not None:
print("Only left available")
return self.left.solve(~0, xi)
else:
print("None available")
return -1
def build_trie(nums):
nums.sort()
# msb of max(nums)
max_bit = int(math.log(nums[-1], 2)) # I'll just assume that nums is never empty
print(max_bit)
def node(start, end, bit, template):
print(start, end, bit, template, nums[start:end])
if end - start == 1:
# reached a leaf
return Trie(0, nums[start], nums[start])
elif start == end:
# a partition without values => no Trie-node
return None
# find pivot for partitioning based on bit-value of specified position (bit)
part = bisect.bisect_left(nums, template | (1 << bit), start, end)
print(part)
# build nodes for paritioning
res = Trie(bit, None, nums[start])
res.left = node(start, part, bit - 1, template)
res.right = node(part, end, bit - 1, template | (1 << bit))
return res
return node(0, len(nums), max_bit, 0)
class Solution:
def maximizeXor(self, nums: List[int], queries: List[List[int]]) -> List[int]:
trie = build_trie(nums)
return [trie.solve(mi if mi <= nums[-1] else ~0, xi) for xi, mi in queries]
I've been a bit lazy and simply used ~0 to signify that the maximum can be ignored since all values in the subtree are smaller than mi. The basic idea is that ~0 & x == x is true for any integer x. Not quite as simple as #DanielHao's answer, but capable of handling streams of queries.

Related

Dynamic Programming for shortest subsequence that is not a subsequence of two strings

Problem: Given two sequences s1 and s2 of '0' and '1'return the shortest sequence that is a subsequence of neither of the two sequences.
E.g. s1 = '011' s2 = '1101' Return s_out = '00' as one possible result.
Note that substring and subsequence are different where substring the characters are contiguous but in a subsequence that needs not be the case.
My question: How is dynamic programming applied in the "Solution Provided" below and what is its time complexity?
My attempt involves computing all the subsequences for each string giving sub1 and sub2. Append a '1' or a '0' to each sub1 and determine if that new subsequence is not present in sub2.Find the minimum length one. Here is my code:
My Solution
def get_subsequences(seq, index, subs, result):
if index == len(seq):
if subs:
result.add(''.join(subs))
else:
get_subsequences(seq, index + 1, subs, result)
get_subsequences(seq, index + 1, subs + [seq[index]], result)
def get_bad_subseq(subseq):
min_sub = ''
length = float('inf')
for sub in subseq:
for char in ['0', '1']:
if len(sub) + 1 < length and sub + char not in subseq:
length = len(sub) + 1
min_sub = sub + char
return min_sub
Solution Provided (not mine)
How does it work and its time complexity?
It looks that the below solution looks similar to: http://kyopro.hateblo.jp/entry/2018/12/11/100507
def set_nxt(s, nxt):
n = len(s)
idx_0 = n + 1
idx_1 = n + 1
for i in range(n, 0, -1):
nxt[i][0] = idx_0
nxt[i][1] = idx_1
if s[i-1] == '0':
idx_0 = i
else:
idx_1 = i
nxt[0][0] = idx_0
nxt[0][1] = idx_1
def get_shortest(seq1, seq2):
len_seq1 = len(seq1)
len_seq2 = len(seq2)
nxt_seq1 = [[len_seq1 + 1 for _ in range(2)] for _ in range(len_seq1 + 2)]
nxt_seq2 = [[len_seq2 + 1 for _ in range(2)] for _ in range(len_seq2 + 2)]
set_nxt(seq1, nxt_seq1)
set_nxt(seq2, nxt_seq2)
INF = 2 * max(len_seq1, len_seq2)
dp = [[INF for _ in range(len_seq2 + 2)] for _ in range(len_seq1 + 2)]
dp[len_seq1 + 1][len_seq2 + 1] = 0
for i in range( len_seq1 + 1, -1, -1):
for j in range(len_seq2 + 1, -1, -1):
for k in range(2):
if dp[nxt_seq1[i][k]][nxt_seq2[j][k]] < INF:
dp[i][j] = min(dp[i][j], dp[nxt_seq1[i][k]][nxt_seq2[j][k]] + 1);
res = ""
i = 0
j = 0
while i <= len_seq1 or j <= len_seq2:
for k in range(2):
if (dp[i][j] == dp[nxt_seq1[i][k]][nxt_seq2[j][k]] + 1):
i = nxt_seq1[i][k]
j = nxt_seq2[j][k]
res += str(k)
break;
return res
I am not going to work it through in detail, but the idea of this solution is to create a 2-D array of every combinations of positions in the one array and the other. It then populates this array with information about the shortest sequences that it finds that force you that far.
Just constructing that array takes space (and therefore time) O(len(seq1) * len(seq2)). Filling it in takes a similar time.
This is done with lots of bit twiddling that I don't want to track.
I have another approach that is clearer to me that usually takes less space and less time, but in the worst case could be as bad. But I have not coded it up.
UPDATE:
Here is is all coded up. With poor choices of variable names. Sorry about that.
# A trivial data class to hold a linked list for the candidate subsequences
# along with information about they match in the two sequences.
import collections
SubSeqLinkedList = collections.namedtuple('SubSeqLinkedList', 'value pos1 pos2 tail')
# This finds the position after the first match. No match is treated as off the end of seq.
def find_position_after_first_match (seq, start, value):
while start < len(seq) and seq[start] != value:
start += 1
return start+1
def make_longer_subsequence (subseq, value, seq1, seq2):
pos1 = find_position_after_first_match(seq1, subseq.pos1, value)
pos2 = find_position_after_first_match(seq2, subseq.pos2, value)
gotcha = SubSeqLinkedList(value=value, pos1=pos1, pos2=pos2, tail=subseq)
return gotcha
def minimal_nonsubseq (seq1, seq2):
# We start with one candidate for how to start the subsequence
# Namely an empty subsequence. Length 0, matches before the first character.
candidates = [SubSeqLinkedList(value=None, pos1=0, pos2=0, tail=None)]
# Now we try to replace candidates with longer maximal ones - nothing of
# the same length is better at going farther in both sequences.
# We keep this list ordered by descending how far it goes in sequence1.
while candidates[0].pos1 <= len(seq1) or candidates[0].pos2 <= len(seq2):
new_candidates = []
for candidate in candidates:
candidate1 = make_longer_subsequence(candidate, '0', seq1, seq2)
candidate2 = make_longer_subsequence(candidate, '1', seq1, seq2)
if candidate1.pos1 < candidate2.pos1:
# swap them.
candidate1, candidate2 = candidate2, candidate1
for c in (candidate1, candidate2):
if 0 == len(new_candidates):
new_candidates.append(c)
elif new_candidates[-1].pos1 <= c.pos1 and new_candidates[-1].pos2 <= c.pos2:
# We have found strictly better.
new_candidates[-1] = c
elif new_candidates[-1].pos2 < c.pos2:
# Note, by construction we cannot be shorter in pos1.
new_candidates.append(c)
# And now we throw away the ones we don't want.
# Those that are on their way to a solution will be captured in the linked list.
candidates = new_candidates
answer = candidates[0]
r_seq = [] # This winds up reversed.
while answer.value is not None:
r_seq.append(answer.value)
answer = answer.tail
return ''.join(reversed(r_seq))
print(minimal_nonsubseq('011', '1101'))

K product array

I am working on an algorithms problem. You have an array numbers, size of array t , number number_of_elements and number multiplication_value. You have to find any set of number_of_elements indexes of the elements of the array , which product will be equal to multiplication_value. It is guaranteed, that such set of indexes exists
That problem looks like 2 sum, but I can't extrapolate it to my case.
I have tried naive algorithm for O(n), but it fails, when you have bad first number in an array. I think there is a way to use recursion in here. I guess it is well-known problem, but I couldn't find the solution
Example in:
t = 7
number_of_elements = 2
multiplication_value = 27
numbers = [9,1,1,27,3,27,3]
Example out:
1 3
My code ideas:
def return_index_values(numbers,multiplication_value,number_of_elements):
cur_number = int(multiplication_value)
list_of_indexes = []
values = []
for i in range(len(numbers)):
if ((cur_number == 1) and (len(values) == number_of_elements)):
print(values)
#finishing if everything worked
break
else:
if (cur_number % int(numbers[i]) == 0):
if(len(values) < number_of_elements):
#pushing values if possible
values.append(int(numbers[i]))
list_of_indexes.append(i)
cur_number = int(cur_number / int(numbers[i]))
print(cur_number)
else:
pass
if(len(values) == number_of_elements):
if mult_check(values,int(multiplication_value)):
#mult_check checks if the array's element multiplication gives a value
break
else:
#started dealing with bad cases, but it doesn't work properly
values.sort()
val_popped = values.pop()
cur_number = cur_number * val_popped
Bad case for my code
numbers = [9,3,1,27,3,27,3]
Here is one implementation. Not necessarily the best solution but it gives you some sense of how it can be done.
It first sorts the numbers by the element keeping the indices information. Then it performs recursion calls.
number_of_elements = 2
multiplication_value = 27
numbers = [9,1,1,27,3,27,3]
def preprocess(numbers, multiplication_value, number_of_elements):
l = []
for i, num in enumerate(numbers):
l.append((num, i))
return sorted(l, key = lambda tup: tup[0])
def subroutine(numbers, multiplication_value, number_of_elements, idx_start, result):
if idx_start >= len(numbers):
return False
if number_of_elements == 0:
return True if multiplication_value == 1 else False
for i in range(idx_start, len(numbers)):
num = numbers[i][0]
if num <= multiplication_value:
if multiplication_value % num == 0:
idx = numbers[i][1]
result.append(idx)
found = subroutine(numbers, multiplication_value / num, number_of_elements - 1, i + 1, result)
if not found:
del result[-1]
else:
return True
else:
return False
return False
result = []
processed_numbers = preprocess(numbers, multiplication_value, number_of_elements)
subroutine(processed_numbers, multiplication_value, number_of_elements, 0, result)
print(result)
You can use itertools.combinations() (https://www.geeksforgeeks.org/itertools-combinations-module-python-print-possible-combinations/) to select number_of_elements entries from your list in all possible ways, then check each whether they multiply to the required number.

Recursive solution to common longest substring between two strings

I am trying to return the length of a common substring between two strings. I'm very well aware of the DP solution, however I want to be able to solve this recursively just for practice.
I have the solution to find the longest common subsequence...
def get_substring(str1, str2, i, j):
if i == 0 or j == 0:
return
elif str1[i-1] == str2[j-1]:
return 1 + get_substring(str1, str2, i-1, j-1)
else:
return max(get_substring(str1, str2, i, j-1), get_substring(str1, str2, j-1, i))
However, I need the longest common substring, not the longest common sequence of letters. I tried altering my code in a couple of ways, one being changing the base case to...
if i == 0 or j == 0 or str1[i-1] != str2[j-1]:
return 0
But that did not work, and neither did any of my other attempts.
For example, for the following strings...
X = "AGGTAB"
Y = "BAGGTXAYB"
print(get_substring(X, Y, len(X), len(Y)))
The longest substring is AGGT.
My recursive skills are not the greatest, so if anybody can help me out that would be very helpful.
package algo.dynamic;
public class LongestCommonSubstring {
public static void main(String[] args) {
String a = "AGGTAB";
String b = "BAGGTXAYB";
int maxLcs = lcs(a.toCharArray(), b.toCharArray(), a.length(), b.length(), 0);
System.out.println(maxLcs);
}
private static int lcs(char[] a, char[] b, int i, int j, int count) {
if (i == 0 || j == 0)
return count;
if (a[i - 1] == b[j - 1]) {
count = lcs(a, b, i - 1, j - 1, count + 1);
}
count = Math.max(count, Math.max(lcs(a, b, i, j - 1, 0), lcs(a, b, i - 1, j, 0)));
return count;
}
}
You need to recurse on each separately. Which is easier to do if you have multiple recursive functions.
def longest_common_substr_at_both_start (str1, str2):
if 0 == len(str1) or 0 == len(str2) or str1[0] != str2[0]:
return ''
else:
return str1[0] + longest_common_substr_at_both_start(str1[1:], str2[1:])
def longest_common_substr_at_first_start (str1, str2):
if 0 == len(str2):
return ''
else:
answer1 = longest_common_substr_at_both_start (str1, str2)
answer2 = longest_common_substr_at_first_start (str1, str2[1:])
return answer2 if len(answer1) < len(answer2) else answer1
def longest_common_substr (str1, str2):
if 0 == len(str1):
return ''
else:
answer1 = longest_common_substr_at_first_start (str1, str2)
answer2 = longest_common_substr(str1[1:], str2)
return answer2 if len(answer1) < len(answer2) else answer1
print(longest_common_substr("BAGGTXAYB","AGGTAB") )
I am so sorry. I didn't have time to convert this into a recursive function. This was relatively straight forward to compose. If Python had a fold function a recursive function would be greatly eased. 90% of recursive functions are primitive. That's why fold is so valuable.
I hope the logic in this can help with a recursive version.
(x,y)= "AGGTAB","BAGGTXAYB"
xrng= range(len(x)) # it is used twice
np=[(a+1,a+2) for a in xrng] # make pairs of list index values to use
allx = [ x[i:i+b] for (a,b) in np for i in xrng[:-a]] # make list of len>1 combinations
[ c for i in range(len(y)) for c in allx if c == y[i:i+len(c)]] # run, matching x & y
...producing this list from which to take the longest of the matches
['AG', 'AGG', 'AGGT', 'GG', 'GGT', 'GT']
I didn't realize getting the longest match from the list would be a little involved.
ls= ['AG', 'AGG', 'AGGT', 'GG', 'GGT', 'GT']
ml= max([len(x) for x in ls])
ls[[a for (a,b) in zip(range(len(ls)),[len(x) for x in ls]) if b == ml][0]]
"AGGT"

Finding out the middle point in mergesort in Python

I have written two different implementations of mergesort algo with only one difference, that of formula used in finding the middle point of the array to divide it.
First implementation : (Runs correctly)
def mergesort(arr):
start = 0
end = len(arr) - 1
if len(arr) > 1:
mid = int(len(arr)/2)
left = mergesort(arr[:mid])
right = mergesort(arr[mid:])
return merge(left,right)
else:
return arr
def merge(left,right):
final = []
while len(left) > 0 or len(right) > 0:
if len(left) > 0 and len(right) > 0:
if left[0] < right[0]:
final.append(left[0])
del left[0]
elif right[0] < left[0]:
final.append(right[0])
del right[0]
elif len(right) > 0:
final.extend(right)
right = []
elif len(left) > 0:
final.extend(left)
left = []
return final
arr = list(map(int,input().split(' ')))
print ("List before sorting:",arr)
final = mergesort(arr)
print ("After sorting:",final)
Second implementation (Gets into an infinite loop):
def mergesort(arr):
start = 0
end = len(arr) - 1
if len(arr) > 1:
mid = int(start + (end - start)/2)
left = mergesort(arr[:mid])
right = mergesort(arr[mid:])
return merge(left,right)
else:
return arr
def merge(left,right):
final = []
while len(left) > 0 or len(right) > 0:
if len(left) > 0 and len(right) > 0:
if left[0] < right[0]:
final.append(left[0])
del left[0]
elif right[0] < left[0]:
final.append(right[0])
del right[0]
elif len(right) > 0:
final.extend(right)
right = []
elif len(left) > 0:
final.extend(left)
left = []
return final
arr = list(map(int,input().split(' ')))
print ("List before sorting:",arr)
final = mergesort(arr)
print ("After sorting:",final)
I have seen the second formula used in case of quicksort algo. The question is if my objective is to divide the array (as in the case of quicksort) why does it goes into an infinite loop.
I am very puzzled and can not come to any logical conclusion.
Can someone please throw some light into the matter? Thanks a lot in advance.
The second method should be used when working with a single array rather than multiple instances of a sub-array. Instead of using actual separate sub-arrays, the original array is split into logical sub-arrays via an index range. The mergesort function would take 3 parameters, mergesort(arr, start, end), and the caller would call mergesort(arr, 0, len(arr)). The merge function would take 4 parameters, merge(arr, start, mid, end).
Efficiency could be improved using an entry function that takes one parameter, mergesort(arr). It would allocate a single working array tmp and pass that to the internal functions, the call from mergesort(arr) would be mergesort(arr, tmp, 0, len(arr)). The mergesort function would be mergesort(arr, tmp, start, end). The merge function would be merge(arr, tmp, start, mid, end).

How to do multiplication by using successor and predecessor in Scala

I am a beginner of programming language. Right now, I am working on a Scala project, which requires us to calculate the sum of the product and the exponentiation of two non-negative integers without using any Math functions and signs but only allows to use successor and predecessor. The functions do count for us. So I need to define addition in terms of those two integers, then define multiplication in terms of addition and exponents in terms of multiplication. So far, I've only come up with the solution for getting sum. Could you please help me to obtain the other parts? I think (if firstNum = 1, secondNum = 3) the product of these two can be obtained by using sum_1(sum_1(sum_1(a,0),a),a) But I really don't know how to write it in Scala code. Many thanks!
import io.StdIn._
val num = readLine("\n\nFor counting the sum, multiplication and exponentiation of two integers.\nPlease enter those two integers in (x,y) format: ")
val comma = num.indexOf(",")
val last = num.indexOf(")")
val firstNum = num.substring(1,comma).toInt
val secondNum = num.substring(comma+1,last).toInt
def sum_1(a:Int,b:Int): Int = {
def succ(a:Int): Int = a + 1
def pred(b:Int): Int = b - 1
if (b < 1) a
else {
succ(a)
pred(b)
sum_1(succ(a), pred(b))
}
}
//multiplication
//exponentation
println("1.The sum is " + sum_1(firstNum, secondNum) + ".")
println("2.The multiplication is .")
println("3.The exponentation is .")
You will have the following set of functions:
def succ(a:Int) = a+1
def pred(a:Int) = a-1
def sum(a:Int,b:Int):Int =
if(b<1) a
else sum(succ(a),pred(b))
def mul(a:Int,b:Int):Int =
if(b==0) 0
else if(b==1) a
else sum(mul(a,pred(b)),a)
def exp(a:Int, b:Int):Int =
if(b<1) 1
else mul(exp(a,pred(b)),a)
object mult extends App {
def succ(a: Int): Int = a + 1
def pred(b: Int): Int = b - 1
def sum(a: Int, b: Int): Int =
if (a == 0) b else sum(pred(a), succ(b))
def mult(a: Int, b: Int): Int =
if (a == 0) 0 else if (a == 1) b else sum(mult(pred(a), b), b)
def exp(a: Int, b: Int): Int =
if (b == 0) 1 else if (b == 1) a else mult(exp(a, pred(b)), a)
def printmult(a: Int, b: Int): Unit = println(s"$a * $b = ${mult(a, b)}")
(0 to 3).foreach { a => (0 to 3).foreach { b => printmult(a, b) } }
def printexp(a: Int, b: Int): Unit = println(s"$a ^ $b = ${exp(a, b)}")
(0 to 3).foreach { a => (0 to 3).foreach { b => printexp(a, b) } }
}

Resources