Given a linked list, rotate the list to the right by k places, where k is non-negative.
Here are some examples:
Input: 1->2->3->4->5->NULL, k = 2
Output: 4->5->1->2->3->NULL
Explanation:
rotate 1 steps to the right: 5->1->2->3->4->NULL
rotate 2 steps to the right: 4->5->1->2->3->NULL
Input: 0->1->2->NULL, k = 4
Output: 2->0->1->NULL
Explanation:
rotate 1 steps to the right: 2->0->1->NULL
rotate 2 steps to the right: 1->2->0->NULL
rotate 3 steps to the right: 0->1->2->NULL
rotate 4 steps to the right: 2->0->1->NULL
Code:
class Solution:
def rotateRight(self, head: ListNode, k: int) -> ListNode:
if k < 0:
return head
if head is None or head.next is None:
return head
it = head
while k != 0:
while it.next.next is not None:
it = it.next
temp = it.next
it.next = None
temp.next = head
head = temp
it = head
k -= 1
return head
The above code is working fine for k < 2000000.
The test case that is failing is -
Last executed input:
[1,2,3]
2000000000
Error: Time Limit Exceeded
The time complexity will be O(k* length of the list), correct?
Related
When working with binary search algorithms, one updates one of the two pointers at each iteration.
However, there are cases like the LeetCode problem where this would miss the solution.
For example, the following solution of threeSumClosest works
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
nums.sort()
distance = float("inf")
for idx, num in enumerate(nums):
if num >= target:
l = 0
r = idx - 1
else:
l = idx + 1
r = len(nums) -1
while l < r:
res = num + nums[l] + nums[r]
if abs(target-res) < abs(distance):
distance = target - res
if res < target:
l +=1
else:
r -= 1
return target - distance
However, computing mid and using l = mid + 1 or r = mid - 1 misses the solution. How do you handle these cases?
I was expecting that updating l or r to mid +1 or mid -1 the algorithm would find the right solution
This question also appears in other forms, like finding the floor/ceiling of a number in a sorted list, or finding the insertion point of a number in a sorted list. In normal binary search if the middle element doesn’t match the predicate we look left or right, but in all of these problems we need to include it.
For example, given list [1, 2, 4], find insertion point of 3.
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
lo = 0
hi = len(nums) - 1
while lo < hi:
mid = lo + (hi - lo) // 2
if nums[mid] == target:
return mid
if nums[mid] < target:
lo = mid + 1
else:
hi = mid
return lo + int(nums[lo] < target)
Given a singly linked list, i am trying to reverse k nodes at a time through out the list.
So, if k = 2, 1 -> 2 -> 3 -> 4 -> 5 -> 6 will turn into 2 -> 1 -> 4 -> 3 -> 6 -> 5. It is assumed that k is always a factor of the length of the list (Length of the list is divisible by k).
I am trying to solve this using an iterative approach rather than a recursive one. I am trying to parse the list as sets of k nodes and reverse them each till the end of the list. This is my code
def reverseList(A, B): # param A : head node of linked list, param B : integer, return the head node in the list
if B < 2:
return A
dummy = ListNode('dummy')
dummy.next = A
prev, behind = dummy, A
while behind:
ahead = behind
for i in range(B-1):
ahead = ahead.next
new_behind = reverse_list(behind, ahead)
prev.next = ahead
behind.next = new_behind
behind = behind.next
return dummy.next
The reverse_list function reverses the list from the start to end nodes of a k set and returns the node at the beginning of the new k set of nodes (the new start node)
def reverse_list(start, end):
prev, curr = None, start
while prev is not end:
next = curr.next
curr.next = prev
prev = curr
curr = next
return curr
The definition of ListNode class
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
When the values A = [ 6 -> 10 -> 0 -> 3 -> 4 -> 8 ] and B = 3 are given, the output is 8 -> 4 -> 3. What exactly am I missing or overlooking? Any help is greatly appreciated.
For each iteration, you should point the next node of the current node to the next node of the next node, then point the next node of the next node to the head node, and then point the head node to the next node, to complete a reversal of the give number of nodes. Then assign the current node as the new head, repeat the above, until the next node of the head is None:
def reverseList(A, B):
head = A
while head.next:
node = head.next
for _ in range(B - 1):
next_node = node.next
if next_node:
node.next = next_node.next
next_node.next = head.next
head.next = next_node
head = node
return A
Demo: https://repl.it/#blhsing/ElatedSurefootedFilesize
I've figured out the mistake i've been making. I didn't update the 'prev' pointer while updating the 'behind' pointer. It should have been
prev = behind
After getting the behind and ahead pointers, this should be the block of code within the while loop in reverseList function
new_behind = reverse_list(behind, ahead)
prev.next = ahead
behind.next = new_behind
prev = behind
behind = behind.next
I am trying to count the numbers of nodes in a linked list when the node value is a non-negative odd, but it seems that I couldn't get the right result.
class Solution:
"""
#param head:
#return: nothing
"""
def countNodesII(self, head):
count = 0
while head.next is not None:
head = head.next
if head.val > 0 and head.val % 2 != 0:
count += 1
else:
return 0
return count
if the input is 1->3->5->null
I expect to get result of 3, but my program returned 2 instead.
Some issues in your code
You would want to move to next node via head=head.next after you check the head node for the condition, right now you are skipping head
You would want to remove return from else, and only return count at the end
You want to check if head reaches None since you are using it to iterate over your list
So the updated code will look like
class Solution:
"""
#param head:
#return: nothing
"""
def countNodesII(self, head):
count = 0
#Iterate over the list
while head != None:
#Check for condition
if head.val > 0 and head.val % 2 != 0:
count += 1
#Move to next node
head = head.next
return count
I am trying to solve the 3 Sum problem stated as:
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
Here is my solution to this problem:
def threeSum(nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort()
n = len(nums)
solutions = []
for i, num in enumerate(nums):
if i > n - 3:
break
left, right = i+1, n-1
while left < right:
s = num + nums[left] + nums[right] # check if current sum is 0
if s == 0:
new_solution = [num, nums[left], nums[right]]
# add to the solution set only if this triplet is unique
if new_solution not in solutions:
solutions.append(new_solution)
right -= 1
left += 1
elif s > 0:
right -= 1
else:
left += 1
return solutions
This solution works fine with a time complexity of O(n**2 + k) and space complexity of O(k) where n is the size of the input array and k is the number of solutions.
While running this code on LeetCode, I am getting TimeOut error for arrays of large size. I would like to know how can I further optimize my code to pass the judge.
P.S: I have read the discussion in this related question. This did not help me resolve the issue.
A couple of improvements you can make to your algorithm:
1) Use sets instead of a list for your solution. Using a set will insure that you don't have any duplicate and you don't have to do a if new_solution not in solutions: check.
2) Add an edge case check for an all zero list. Not too much overhead but saves a HUGE amount of time for some cases.
3) Change enumerate to a second while. It is a little faster. Weirdly enough I am getting better performance in the test with a while loop then a n_max = n -2; for i in range(0, n_max): Reading this question and answer for xrange or range should be faster.
NOTE: If I run the test 5 times I won't get the same time for any of them. All my test are +-100 ms. So take some of the small optimizations with a grain of salt. They might NOT really be faster for all python programs. They might only be faster for the exact hardware/software config the tests are running on.
ALSO: If you remove all the comments from the code it is a LOT faster HAHAHAH like 300ms faster. Just a funny side effect of however the tests are being run.
I have put in the O() notation into all of the parts of your code that take a lot of time.
def threeSum(nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
# timsort: O(nlogn)
nums.sort()
# Stored val: Really fast
n = len(nums)
# Memory alloc: Fast
solutions = []
# O(n) for enumerate
for i, num in enumerate(nums):
if i > n - 3:
break
left, right = i+1, n-1
# O(1/2k) where k is n-i? Not 100% sure about this one
while left < right:
s = num + nums[left] + nums[right] # check if current sum is 0
if s == 0:
new_solution = [num, nums[left], nums[right]]
# add to the solution set only if this triplet is unique
# O(n) for not in
if new_solution not in solutions:
solutions.append(new_solution)
right -= 1
left += 1
elif s > 0:
right -= 1
else:
left += 1
return solutions
Here is some code that won't time out and is fast(ish). It also hints at a way to make the algorithm WAY faster (Use sets more ;) )
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
# timsort: O(nlogn)
nums.sort()
# Stored val: Really fast
n = len(nums)
# Hash table
solutions = set()
# O(n): hash tables are really fast :)
unique_set = set(nums)
# covers a lot of edge cases with 2 memory lookups and 1 hash so it's worth the time
if len(unique_set) == 1 and 0 in unique_set and len(nums) > 2:
return [[0, 0, 0]]
# O(n) but a little faster than enumerate.
i = 0
while i < n - 2:
num = nums[i]
left = i + 1
right = n - 1
# O(1/2k) where k is n-i? Not 100% sure about this one
while left < right:
# I think its worth the memory alloc for the vars to not have to hit the list index twice. Not sure
# how much faster it really is. Might save two lookups per cycle.
left_num = nums[left]
right_num = nums[right]
s = num + left_num + right_num # check if current sum is 0
if s == 0:
# add to the solution set only if this triplet is unique
# Hash lookup
solutions.add(tuple([right_num, num, left_num]))
right -= 1
left += 1
elif s > 0:
right -= 1
else:
left += 1
i += 1
return list(solutions)
I benchamrked the faster code provided by PeterH but I found a faster solution, and the code is simpler too.
class Solution(object):
def threeSum(self, nums):
res = []
nums.sort()
length = len(nums)
for i in xrange(length-2): #[8]
if nums[i]>0: break #[7]
if i>0 and nums[i]==nums[i-1]: continue #[1]
l, r = i+1, length-1 #[2]
while l<r:
total = nums[i]+nums[l]+nums[r]
if total<0: #[3]
l+=1
elif total>0: #[4]
r-=1
else: #[5]
res.append([nums[i], nums[l], nums[r]])
while l<r and nums[l]==nums[l+1]: #[6]
l+=1
while l<r and nums[r]==nums[r-1]: #[6]
r-=1
l+=1
r-=1
return res
https://leetcode.com/problems/3sum/discuss/232712/Best-Python-Solution-(Explained)
When I try to make the next attribute of a node, p, of a linked list point to None, I use p.next = None. But what if I want to make the node corresponding to p.next to None?
An example would be when try to rotate a linked list, which ends with a node's next equal to None, I want to make the new list's last element's next point to None but I think I keep deleting the element that it pointed to.
Here's my code for rotating the list by k positions. If you want to see the full description of the problem see here
def rotate(head, k):
'''
head is pointer to the head, k is the number of positions to rotate
'''
if not head or k == 0:
return head
p = head
d = head
counter = 1
while p.next != None:
counter += 1
p = p.next
out = ListNode(0)
if k % counter == 0:
return head
if counter < k:
counter = counter % k
for _ in range(counter):
p.next = d
d = d.next
p = p.next
out = p
d.next.next = None
return out
Sounds like you want to take the last k values and append them to the front.
p.next is the next node. In general when we want to change p's next we need to grab temp = p.next p.next = newNode and then we can continue.
In this case though, I'd find the length of the list, set tail.next = head, subtract k (accounting for wraparound), then walk forward till N-k, and set that node's p.next = None
Something like:
p, len, prev = head, 0, None
while p:
prev = p
p = p.next
len += 1
# prev is tail, set it's next to head
prev.next = head
# find the node to detach
p = head
for i in xrange(len):
p = p.next
p.next = None
You'll need to figure out corner cases