- Identify the ordered answer range or sorted search domain.
- Write a predicate whose truth changes only once.
- Move the appropriate boundary after each midpoint check and return the final feasible position.
Code notes
- 65 lines of Python from the credited upstream file lexicographically-smallest-string-after-reverse-ii.py.
- The implementation keeps its working state in language-native values and containers.
- No explicit loop blocks detected.
Complexity
Multiply the logarithmic number of midpoint checks by the cost of one predicate evaluation.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
123 45class Solution(object):6 def lexSmallest(self, s):7 """8 :type s: str9 :rtype: str10 """11 MOD = 10**9+712 B = 2913 def binary_search(left, right, check):14 while left <= right:15 mid = left+(right-left)216 if check(mid):17 right = mid-118 else:19 left = mid+120 return left21 22 def get_prefix_hash(l, r):23 return (prefix[r+1]-prefix[l]*base[r-l+1])%MOD if l <= r else 024 25 def get_suffix_hash(l, r):26 return (suffix[l]-suffix[r+1]*base[r-l+1])%MOD if l <= r else 027 28 def get_total_hash(k, t, l):29 if not t:30 return get_suffix_hash(k-l, k-1) if l <= k else ((get_suffix_hash(0, k-1))*base[l-k]+get_prefix_hash(k, l-1))%MOD31 nk = len(s)-k32 return get_prefix_hash(0, l-1) if l <= nk else ((get_prefix_hash(0, nk-1))*base[l-nk]+get_suffix_hash(len(s)-(l-nk), len(s)-1))%MOD33 34 def get_char(k, t, idx):35 if not t:36 return s[(k-1)-idx] if idx < k else s[idx]37 return s[idx] if idx < len(s)-k else s[(len(s)-1)-(idx-(len(s)-k))]38 39 def is_less(k, i):40 idx = binary_search(0, len(s)-1, lambda x: get_total_hash(k, i, x+1) != get_total_hash(best_k, best_i, x+1))41 return idx != len(s) and get_char(k, i, idx) < get_char(best_k, best_i, idx)42 43 prefix = [0]*(len(s)+1)44 for i in xrange(len(prefix)-1):45 prefix[i+1] = (prefix[i]*B+ord(s[i]))%MOD46 suffix = [0]*(len(s)+1)47 for i in reversed(xrange(len(suffix)-1)):48 suffix[i] = (suffix[i+1]*B+ord(s[i]))%MOD49 base = [1]*(len(s)+1)50 for i in xrange(len(base)-1):51 base[i+1] = (base[i]*B)%MOD52 best_k, best_i = 1, 053 mn = min(s)54 for k in xrange(1, len(s)+1):55 if s[k-1] != mn:56 continue57 if is_less(k, 0):58 best_k, best_i = k, 059 for k in xrange(1, len(s)+1):60 if not s[-k] >= s[-1]:61 continue62 if is_less(k, 1):63 best_k, best_i = k, 164 return s[:best_k][::-1]+s[best_k:] if not best_i else s[:-best_k]+s[-best_k:][::-1]65