Prerequsites : Binary Search(Vanilla) , Find the First True in a Sorted Boolean Array , Ceiling(Upper Bound)
Question
You are given an array of character letters
that is sorted in non-decreasing order and a character target
. (There are at least two different characters in letters
. i.e [char1,char2])
Return the smallest character in letters
that is lexicographically greater than the target
. If such a character does not exist, return the first character in letters
.
Example 1:
Input: letters = ["a","b","f","g","h","i"], target = "g"
Output: "c"
Explanation: The smallest character that is lexicographically greater than 'g' in letters is 'h'.
Example 2:
Input: letters = ["c","f","j"], target = "c"
Output: "f"
Explanation: The smallest character that is lexicographically greater than 'c' in letters is 'f'.
Example 3:
Input: letters = ["x","x","y","y"], target = "z"
Output: "x"
Explanation: There are no characters in letters that is lexicographically greater than 'z' so we return letters[0].
Leetcode
Intuition
- The array is sorted, providing us with our first clue that we can solve this problem using binary search.
- All the values that are greater (lexicographically) than the target will be on the right side of the target. All the values less than and equal to the target will be on the left side.
- This gives us our two halves.
- when we are in the upper half; get rid of all elements to the right, when in the lower half; get rid of all elements to the left.
- We hop between each half-chopping element and reduce the range. The last element we will chop from the upper half will be the smallest character greater/after than target. We keep updating the possible value and return the most up-to-date.
- We end up returning the smallest element after the target in the upper half, as we did in Ceiling(Upper Bound)
- There are a few things slightly different from Ceiling(Upper Bound)
- Alphabet instead of numbers. ( >(greater than) sign still works for alphabets)
- The smallest element in letters strictly greater than the target
- Previously we included the target as a potential ceil.
- If such a character does not exist, return the first character in
letters
. - If the left and right pointers overlap without finding the ceil we return the first character.
Code for Ceiling(Upper Bound)
class Solution:
def ceil(self,nums,target):
left, right = 0, len(nums) - 1
ceil = -1
while left <= right:
mid = left + (right - left) // 2
#True
# Possible Value
if nums[mid] >= target:
ceil = mid
right = mid - 1
# False
else: # target > nums[mid]
left = mid + 1
# if not found will return -1
return ceil
Code for this Question with Changes
class Solution:
def nextGreatestLetter(self, letters, target):
left,right = 0,len(letters)-1
res = "@" # change
while left <= right:
mid = left + (right-left)//2
#True
# Possible Value
if letters[mid] > target: #change
res = letters[mid]
right = mid -1
# False
else: #letters[mid] <= target:
left = mid + 1
# if not found will return the first letter
return res if res != "@" else letters[0] #change
SandBox PythonTutor (Visualized)
‣
Complexities
Time Complexity: O(log(n))
Space Complexity: O(1)