Reputation: 21
I am given a sorted array of positive integers and a number X and I need to print out all pairs of numbers whose sum is equal to X. Print out only unique pairs and the pairs should be in ascending order.
However the program needs to read lines of text from standard input where each line contains a comma separated list of sorted numbers, followed by a semicolon, followed by the integer X.
e.g. test input:1,2,3,4,6;5
output: 1,4;2,3
I have tried
list1 = []
for line in sys.stdin:
for n in line:
list1.append(n)
strlist = [ x for x in list1 if x.isdigit() ]
numlist = list(map(int, strlist))
sum = numlist[-1]
res = []
while numlist:
num = numlist.pop()
diff = sum - num
if diff in numlist:
res.append((diff, num))
res.reverse()
print(res, end="")
But i get
Test Input: 1,2,3,4,6;5
Expected Output: 1,4;2,3
My Output: [(2, 3), (1, 4)]
Upvotes: 1
Views: 984
Reputation: 10709
Time complexity of O(n^2)
. This is based on the original solution. The corrections made were:
12
thus it is incorrect. Also it is not efficient. Instead of manually iterating each character, checking .isdigit()
, and then redoing it again for the next number for the whole list, just split the string by the characters ;
and ,
and then transform them to int.numlist
. But you are considering that number for the sum (since it will be the first number to be popped out). You should pop it first before entering the while loop.1
is to 4
, then 2
is to 3
, thus no need to call .reverse()
as it will do the opposite.for input_text in [
"1,2,3,4,6;5",
"5,10,15,20,25,30,35,40,45;50",
"0,2,4,6,8,10,12,14;12",
]:
num_str, sum_str = input_text.split(';')
num_list = list(map(int, num_str.split(',')))
target_sum = int(sum_str)
res = []
while num_list:
num = num_list.pop()
diff = target_sum - num
if diff in num_list:
res.append((diff, num))
res_formatted = ";".join(map(lambda pair: f"{pair[0]},{pair[1]}", res))
print(f"{input_text}\n\t{res}\n\t{res_formatted}")
Time complexity of O(n)
. Since we already have sorted data, instead of iterating the whole list finding the other number that will arrive to the target sum for each number, just use 2 pointers, one at the start/left lhs
and one at the end/right rhs
.
lhs
. Why? Because if we already added it to the maximum number which is rhs
, then there is no point of trying it with the other numbers. What we need is to increase lhs
and see the next result.rhs
. Why? Same point as above, If the sum was already higher, then we can't use the number in rhs
as it is too high even if added with the smallest number lhs
, thus move it to the next smaller number.lhs
and rhs
. Then we move both pointers respectively.def sum_pairs(numbers, target_sum):
lhs = 0
rhs = len(numbers) - 1
pairs = []
while lhs < rhs:
current_sum = numbers[lhs] + numbers[rhs]
if current_sum == target_sum:
pairs.append((numbers[lhs], numbers[rhs]))
lhs += 1
rhs -= 1
elif current_sum > target_sum:
rhs -= 1
else:
lhs += 1
return pairs
for input_text in [
"1,2,3,4,6;5",
"5,10,15,20,25,30,35,40,45;50",
"0,2,4,6,8,10,12,14;12",
]:
num_str, sum_str = input_text.split(';')
num_list = list(map(int, num_str.split(',')))
target_sum = int(sum_str)
res = sum_pairs(num_list, target_sum)
res_formatted = ";".join(map(lambda pair: f"{pair[0]},{pair[1]}", res))
print(f"{input_text}\n\t{res}\n\t{res_formatted}")
Output
1,2,3,4,6;5
[(1, 4), (2, 3)]
1,4;2,3
5,10,15,20,25,30,35,40,45;50
[(5, 45), (10, 40), (15, 35), (20, 30)]
5,45;10,40;15,35;20,30
0,2,4,6,8,10,12,14;12
[(0, 12), (2, 10), (4, 8)]
0,12;2,10;4,8
Upvotes: 1
Reputation: 11
This might not be the most efficient, but I came up with this that worked.
Replace the test_case with sys.stdin and remove the test_case should work.
Sorry if this looks bad, it's my first time posting on stackoverflow.
test_case = ["1,2,3,4,6;5"]
for line in test_case:
line = line.split(";")
numbers = line[0].split(",")
pairs = []
for number in numbers:
difference = int(line[1]) - int(number)
difference = str(difference)
if difference in numbers and difference != number:
pair = ",".join((number, difference))
pairs.append(pair)
del pairs[len(pairs)//2:len(pairs)]
print(";".join(pairs))
Output : 1,4;2,3
Upvotes: 1