Find three Numbers with Sum closest to a given number - python

I am trying to solve a problem where,
Given an array S of n integers, find three integers in S such that the
sum is closest to a given number, target. Return the sum of the three
integers. You may assume that each input would have exactly one
solution.
For example, given array S = {-1 2 1 -4}, and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
My solution is: take a number out (number_1) from the array, set the target to target - that number and find two other numbers which are closest to the new target. This way: number_1 + number_2 + number_3 will be closest as number_2 + number_3 will be closest to target - number_1.
I tried my solution at https://leetcode.com/problems/3sum-closest/description/.
My solution is:
def threeSumClosest(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
closest_sum = nums[0] + nums[1] + nums[2]
for i in range(len(nums)):
# Create temp array excluding a number
if i!=len(nums)-1:
temp = nums[:i] + nums[i+1:]
else:
temp = nums[:len(nums)-1]
# Sort the temp array and set new target to target - the excluded number
temp = sorted(temp)
l, r = 0, len(temp) -1
t = target - nums[i]
while(l<r):
if temp[l] + temp[r] == t:
return target
elif temp[l] + temp[r] > t:
if abs(temp[l] + temp[r] + nums[i] - target) < abs(closest_sum - target):
closest_sum = temp[l] + temp[r] + nums[i]
r = r - 1
else:
if abs(temp[l] + temp[r] + nums[i] - target) < abs(closest_sum - target):
closest_sum = temp[l] + temp[r] + nums[i]
l = l + 1
return closest_sum
It passes 80 test cases out of 125, so the solution logic looks fine enough for me.
It fails for:
Input:
[0,2,1,-3]
1
Output:
3
Expected:
0
Can't understand why it fails and how to make my logic consistent.
Thanks for your help.

You have couple of mistakes the first one is silly, you have an extra indentation in return closest and the second one is not checking updating closest in the 3rd if statement.
This code got accepted:
class Solution(object):
def threeSumClosest(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
closest = nums[0] + nums[1] + nums[2]
#if len(nums)==3:
# return closest
for i in range(len(nums)):
if i!=len(nums)-1:
temp = nums[:i] + nums[i+1:]
else:
temp = nums[:len(nums)-1]
temp = sorted(temp)
l, r = 0, len(temp) -1
t = target - nums[i]
while(l < r):
if abs(temp[l] + temp[r] + nums[i] - target) < abs(closest - target):
closest = temp[l] + temp[r] + nums[i]
if temp[l] + temp[r] == t:
return target
elif temp[l] + temp[r] > t:
r = r - 1
else:
l = l + 1
return closest
And this is an accepted C++ solution with O(n^2) running time:
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int ans = nums[0] + nums[1] + nums[2];
for(int i = 0; i < nums.size() - 2; i++) {
int l = i + 1, r = nums.size() - 1;
while (l < r) {
if(abs(nums[i] + nums[l] + nums[r] - target) < abs(target - ans)) {
ans = nums[i] + nums[l] + nums[r];
}
if(nums[r] + nums[l] > target - nums[i]) r = r - 1;
else l = l + 1;
}
}
return ans;
}
};

As we worked out in the comments the last return statment was erroneously inside the for loop cutting it short after the first iteration.
Also, closest should be updated in both branches where we overshoot or undershoot the target.
I think an obvious improvement of your algorithm would be to sort first. Removing individual elements doesn't destroy order, so you'd need to sort only once. That would get you from O(n^2 log n) to O(n^2).

You can find all combinations of values in the list, and then find the listing whose sum is closest to the target:
import itertools
s = [{'vals':[-1, 2, 1, -4], 'target':1}, {'vals':[0,2,1,-3],'target':1}]
final_result = {tuple(a['vals']):sum(min(itertools.combinations(a['vals'], 3), key=lambda x:abs(a['target']-sum(x)))) for a in s}
Output:
{(-1, 2, 1, -4): 2, (0, 2, 1, -3): 0}

My solution works for this input:
[0,2,1,-3]
1
Your closest sum variable is incorrect. See my variable named "gap"
class Solution:
def threeSumClosest(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
sorted_nums = sorted(nums)
gap = sorted_nums[len(nums)-1] * 10000
solution = 0
for pointer_1 in range(len(sorted_nums)):
pointer_2 = pointer_1 + 1
pointer_3 = len(sorted_nums) - 1
while(pointer_2 < pointer_3):
gap_n = abs((sorted_nums[pointer_1]+sorted_nums[pointer_2]+sorted_nums[pointer_3]) - target)
add = (sorted_nums[pointer_1]+sorted_nums[pointer_2]+sorted_nums[pointer_3])
if (gap_n < gap):
solution = add
gap = gap_n
elif (target > add):
pointer_2 = pointer_2 + 1
else:
pointer_3 = pointer_3 - 1
return solution

Related

How do I calculate the complexity of this leetcode solution?

I worked on on this problem on Leetcode called numbers-with-same-consecutive-differences and have no idea why the runtime for this solution (and many others in the discussion section of that problem) is O(2^N).
class Solution:
def numsSameConsecDiff(self, N, K):
"""
:type N: int
:type K: int
:rtype: List[int]
"""
ans = list(range(1, 10))
for _ in range(N-1):
temp = []
for n in ans:
prev = n % 10
if K == 0:
temp.append(10 * n + prev)
else:
if prev >= K:
temp.append(10 * n + prev - K)
if prev + K <= 9:
temp.append(10 * n + prev + K)
ans = temp[:]
return [0] + ans if N == 1 else ans
I get O(N (length of integers in answers) * n (length of answer) * 2 (the two choices in the else case)), and that is far from O(2^n). Where am I misunderstanding things?

Optimizing the closest 3sum solution to avoid time limit exceeded error

I was going through this closest 3-sum leetcode problem which says:
Given an integer array nums of length n and an integer target, find three integers in nums such that the sum is closest to target.
Return the sum of the three integers.
You may assume that each input would have exactly one solution.
I have created the following solution and this appears correct but it fails with the Time Limit Exceeded error. How could I optimize this code? I have already added one of the optimization I felt but not sure how can I improve this further.
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
nums.sort()
csum = None
min_diff = float("+inf")
for i in range(0,len(nums)-2):
l = i + 1
r = len(nums)-1
if i > 0 and nums[i] == nums[i-1]:
continue # OPTIMIZATION TO AVOID SAME CALCULATION
while l < r:
sum = nums[i] + nums[l] + nums[r]
diff = abs(target-sum)
if sum == target:
csum = target
min_diff = 0
break
elif sum > target:
r -= 1
else:
l += 1
if min_diff > diff:
min_diff = diff
csum = sum
return nums[0] if csum is None else csum
Maybe this reference approach can help: Try it first and see if you have any question. Note - see this from a recent post, it performs really well - exceeds 90% of submission in Python category.
def threeSumClosest(self, nums: List[int], target: int) -> int:
nums.sort()
return self.kSumClosest(nums, 3, target)
def kSumClosest(self, nums: List[int], k: int, target: int) -> int:
N = len(nums)
if N == k: return sum(nums[:k]) # found it
# too small
tot = sum(nums[:k])
if tot >= target: return tot
# too big
tot = sum(nums[-k:])
if tot <= target: return tot
if k == 1:
return min([(x, abs(target - x)) for x in nums], key = lambda x: x[1])[0]
closest = sum(nums[:k])
for i, x in enumerate(nums[:-k+1]):
if i > 0 and x == nums[i-1]:
continue
current = self.kSumClosest(nums[i+1:], k-1, target - x) + x
if abs(target - current) < abs(target - closest):
if current == target:
return target
else:
closest = current
return closest

Given a sorted list of integers of length N, determine if an element x is in the list

The problem to solve is:
Given a sorted list of integers of length N, determine if an element x is in the list without performing any multiplication, division, or bit-shift operations. Do this in O(log N) time.
I have solved this problem using a modified binary search, but I'm not sure if this satisfies the time complexity required. Is there a better solution?
def get_mid(start, end):
mid = start + 1
sum_ = start + end
prev = mid
while mid < end and (mid + mid) != sum_ and (mid + mid + 1) != sum_:
prev = mid
mid += mid
if mid > end:
return prev
return mid
def bin_search(arr, x):
start, end = 0, len(arr) - 1
while start <= end:
mid = get_mid(start, end)
if mid == 1:
return x in arr[:end]
if x > arr[mid]:
start = mid + 1
elif x < arr[mid]:
end = mid - 1
else:
return True
return False
We can find the index of x if it exists by constructing the index bit-by-bit:
def find_idx_sorted(arr, x):
powers_of_two = [1]
while powers_of_two[-1] < len(arr):
powers_of_two.append(powers_of_two[-1] + powers_of_two[-1])
idx = 0
for pot in reversed(powers_of_two):
if idx + pot < len(arr) and x >= arr[idx + pot]:
idx += pot
return idx
Then all we need to do:
def contains_sorted(arr, x):
return arr[find_idx_sorted(arr, x)] == x
Do it in O(logN) time, binary search must be used. So, the key point here is to find a way to do division by 2 without multiplication, division, and bit-shift.
Here is a function to do in constant time:
int divideTwo(int x) {
vector<int> bit = {
0x1, 0x2, 0x4, 0x8,
0x10, 0x20, 0x40, 0x80,
0x100, 0x200, 0x400, 0x800,
0x1000, 0x2000, 0x4000, 0x8000,
0x10000, 0x20000, 0x40000, 0x80000,
0x100000, 0x200000, 0x400000, 0x800000,
0x1000000, 0x2000000, 0x4000000, 0x8000000,
0x10000000, 0x20000000, 0x40000000, 0
};
int v = 0;
for (int i = 1; i < bit.size() - 1 && x > 0; ++i) {
if ((x & bit[i]) > 0)
{
v += bit[i - 1];
x -= bit[i];
}
}
return v;
}
To find with just addition and no loops using log2(N) calls:
def find_pos(step, arr, val):
next = step+step
if next < len(arr):
choose = find_pos(next, arr, val)
else:
choose = step
next = choose + step
if next < len(arr) and arr[next] <= val:
return next
if arr[choose] <= val:
return choose
return 0
def find_val(arr, val):
index = find_pos(1, arr, val)
if arr[index] == val:
print "found %d at %d" % (val, index)
else:
print "%d not found" % (val)

How to reorder digits of a number and insert digit 5 to get the maximum possible absolute value

Please advise how I can reorder digits of a number and add a digit 5 to the result so that its absolute value will be the highest.
For example, if the input is 578 the expected result is 8755. Otherwise, if the input is negative -483, the output is expected to be -8543.
I've managed to make it work on positive numbers only, however, I need to make it work for negative numbers as well:
def solution(N):
a = [] # list of digits, e.g. int(123)
while N != 0:
v = N % 10 # last digit as div remainder, e.g.: 123 % 10 = 3
N = int(N / 10) # remove last digit using integer division: 123 / 10 = 12.3; int(12.3) = 12
a = [v] + a # concatenate two lists: newly created list with one element (v = 3) and list a
# as a result the digits will be in natural order => [1,2,3]
if len(a) == 0: # need to create list with one element [0] as the cycle before ignores 0
a = [0]
inserted = False
for i in range(0, len(a)): # i = 0, 1, 2; len = 3
if a[i] < 5:
# a[from:to exclusive] e.g.: [1, 2, 3][0:2] => [1, 2]. index of 1 is 0, index of 2 is 1, index 2 is excluded
a = a[0:i] + [5] + a[i:]
inserted = True
break
if not inserted:
a = a + [5]
N = 0 # reconstruct number from digits, list of digits to int
for i in range(0, len(a)):
N = N * 10 + a[i] # 0 + 1; 1 * 10 + 2; 12 * 10 + 3 = 123
return N
if __name__ == ‘__main__’:
print(“Solution:”, solution(0))
here i made some major changes by using some inbuilt python methods :
def solution(N):
sign = False #to determine the sign of N (positive or negative )
if N < 0:
sign = True
N= N * -1 # as N<0 we make it positive
a = []
while N != 0:
v = N % 10
N = int(N / 10)
a = [v] + a
a.append(5) # in built method to add an element at the end of the list
a.sort() # in built method to sort the list (ascending order)
a.reverse() # in build method to reverse the order of list (make it descending order)
N = 0
for i in range(0, len(a)):
N = N * 10 + a[i]
if sign: # convert negative integers back to negative
N = N * -1
return N
Sample output :
for negative
solution(-2859)
-98552
positive
solution(9672)
97652
If you need to insert 5 and to make the output number the maximum number both for negative and positive numbers (and without the condition to not replace or transform the input set of digits), then this may be a solution:
def solution(N):
negative = False
if N < 0:
negative = True
N = N * -1 # as N<0 we make it positive
a = []
while N != 0:
v = N % 10
N = int(N / 10)
a = [v] + a
if len(a) == 0:
a = [0]
inserted = False
for i in range(0, len(a)):
if (not negative and a[i] < 5) or (negative and a[i] > 5):
a = a[0:i] + [5] + a [i:]
inserted = True
break
if not inserted:
a = a + [5]
N = 0
for i in range(0, len(a)):
N = N * 10 + a[i]
if negative:
N = N * -1
return N
if __name__ == '__main__':
print("Solution:", solution(N))
Will the below do the trick:
x=-34278
no_to_insert=5
res=int(''.join(sorted(list(str(abs(x)))+[str(no_to_insert)], reverse=True)))
if x<0:
res=-res
Output:
-875432
Java Solution
public int solution(int N) {
int digit = 5;
if (N == 0) return digit * 10;
int neg = N/Math.abs(N);
N = Math.abs(N);
int n = N;
int ctr = 0;
while (n > 0){
ctr++;
n = n / 10;
}
int pos = 1;
int maxVal = Integer.MIN_VALUE;
for (int i=0;i<=ctr;i++){
int newVal = ((N/pos) * (pos*10)) + (digit*pos) + (N%pos);
if (newVal * neg > maxVal){
maxVal = newVal*neg;
}
pos = pos * 10;
}
return maxVal;
}

Given a string S and a set of words D, find the longest word in D that is a subsequence of S

I tried solving this in python 2.7 using regex. I found it to be quite simple. Wondering if I am missing something. Is there an edge case or corner case here?
S = "abppplee"
D = {"able", "ale", "apple", "bale", "kangaroo"}
def subseq(S,D):
# every word in D is made into a regex pattern interspersed with .* and looked up in S
import re
in_dict = {word:len(word) for word in D if bool(re.search(pattern=".*".join(word),string=S))}
return max(in_dict, key=in_dict.get)
subseq(S,D)
returns 'apple'
re.search
Scan through string looking for a match to the pattern, returning a match object, or None if no match was found.
But in your case you need to find the subsequence of string with list.
Code for generating subsequence is
def subsequence(X, Y, m, n):
L = [[0 for x in range(n + 1)] for x in range(m + 1)]
# Following steps build L[m+1][n+1] in bottom up fashion. Note
# that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1]
for i in range(m + 1):
for j in range(n + 1):
if i == 0 or j == 0:
L[i][j] = 0
elif X[i - 1] == Y[j - 1]:
L[i][j] = L[i - 1][j - 1] + 1
else:
L[i][j] = max(L[i - 1][j], L[i][j - 1])
# Following code is used to print LCS
val = L[m][n]
index = L[m][n]
# Create a character array to store the lcs string
lcs = [""] * (index + 1)
lcs[index] = "\0"
# Start from the right-most-bottom-most corner and
# one by one store characters in lcs[]
i = m
j = n
while i > 0 and j > 0:
# If current character in X[] and Y are same, then
# current character is part of LCS
if X[i - 1] == Y[j - 1]:
lcs[index - 1] = X[i - 1]
i -= 1
j -= 1
index -= 1
# If not same, then find the larger of two and
# go in the direction of larger value
elif L[i - 1][j] > L[i][j - 1]:
i -= 1
else:
j -= 1
sequence = "".join(lcs)
return val,sequence
#Driver Code
S = "alnegearoo"
D = {"able", "ale", "apple", "bale", "kangaroo"}
max_len = 0
max_string = ""
for word in D:
subseq_len,match = subsequence(word,S,len(word),len(S))
if(max_len < subseq_len):
max_len = subseq_len
max_string = match
print(max_string)
Output
angaroo
Enjoy Coding....
I did it using java hopefully it can help others to solve it
public String lookFor(String inputWord, String[] dictionary) {
Arrays.sort(dictionary);
for (int index = dictionary.length - 1; index > 0; index--) {
if (isTheWordASubsequence(inputWord, dictionary[index]))
return dictionary[index];
}
return null;
}
private boolean isTheWordASubsequence(String inputWord,
String dictionaryWord) {
int spot = 0;
int offset = 0;
for (char item : dictionaryWord.toCharArray()) {
spot = (offset = inputWord.indexOf(item, spot)) >= spot ? offset : -1;
if (spot < 0)
return false;
}
return true;
}
You should use re.escape.
import re
string = 'abppplee{lkfj3lkj.f*)(*)(*#}dddd.sdf*3j3jj3}####'
words = {'apple', 'ale', 'bale', 'able', 'apple{}.*', 'kangaroo'}
max({word for word in words
if re.search('.*'.join(map(re.escape, word)), string)},
key=len)
I hardly differentiate between answering this question and doing Kata on e.g. Codewars.

Categories

Resources