問題

image-1764471028104.jpgimage-1764471028104.jpg

Code in cpp

思考

Rethinking approach for C++ solution

The search didn't return results, but we already have enough information from the image. For the C++ solution, we need to focus on pairs where reverse(nums[i]) == nums[j] and then find the minimum absolute distance |i - j|. To optimize, we could map values to their indices or use a reversed mapping for quicker lookup. We need to consider both roles while scanning from left to right.

Optimizing approach with index mapping

When at index i, I need to find previous i_prev values such that reverse(nums[i_prev]) == nums[i]. For this, I’ll keep track of the last index of each encountered number. When I reach index j, if the reversed number exists in the map, I can compute the minimal difference between indices i and j. The distance is symmetrical, so iterating in one direction is enough to capture all pairs. We'll store these indices in a map to optimize the search.

Approach to finding mirror pairs efficiently

For each index j, I will reverse nums[j] (denoted rev). If the map contains rev, I compute the candidate distance as j - map[rev] and update the answer with the minimum distance. The map stores the last index for every value of nums[j]. The time complexity is O(n * digits). Since the nearest valid i gives the minimal distance, we only need to store the last index — a vector isn't necessary. I also need to account for edge cases like leading zeros after reversing and signs for negative numbers.

Implementing safe reverseNum function and considerations

The function reverseNum(int x) handles reversing an integer without overflow. For x = 0, the while loop directly returns 0 as expected, so no special treatment is needed. We can safely reverse numbers up to 1e9 without exceeding integer limits. For large numbers, the function won't cause overflow. Using an unordered_map<int, int> for last index mapping is fine, as operations are amortized to O(1).

Considering mirrored pairs and implementing the solution

For palindromic numbers like 11 or 121, the algorithm still works: it searches for reverse matches, ensuring correct indexing (i < j). The problem specifies this order, so we’re good. I’ll provide the code in the format expected for LeetCode as int minMirrorPairDistance(vector<int>& nums) so it's easier for users to copy.

Refining code and confirming logic for mirror pairs

The code looks good for finding the mirror pairs. For each j, we reverse nums[j], look for its reverse in the previous elements, and update the result if we find a valid pair. It works correctly in the sequence and treats i < j. I also confirm edge cases like 11 where reverse check should hold true.

Reevaluating mirror pair check for edge cases

Our previous approach overlooked numbers with trailing zeros, like [10, 1], where the reverse of 10 is 1. The algorithm checked for nums[i] == reverse(nums[j]), but we need reverse(nums[i]) == nums[j]. This highlights the issue with reversing and ignores cases involving leading/trailing zeros, requiring a rework of the logic.

Reevaluating approach to mirror pair checking

For a more efficient solution, I’d precompute the reverse of each number and store it in a map. As we go through the array, I’ll compare the reversed values and track the earliest occurrence of each reversed number while checking for valid pairs. This reduces the O(n^2) approach to a more manageable complexity.

Refining algorithm with pair checks

The approach works by checking if a reversed number matches a later number in the sequence. During each iteration, we either insert the reversed number into a map or find an existing match. This allows us to update the result, ensuring minimal pair distances, while handling complex

Thought for 2m 48s

回答

Here’s a clean C++ solution for “Minimum Absolute Distance Between Mirror Pairs”:

cpp
#include <bits/stdc++.h> using namespace std; class Solution { public: // Reverse digits of a non-negative integer, dropping leading zeros int reverseNum(int x) { int rev = 0; while (x > 0) { rev = rev * 10 + (x % 10); x /= 10; } return rev; } int minMirrorPairDistance(vector<int>& nums) { unordered_map<int,int> lastIndexOfReversed; // value -> last index i with reverse(nums[i]) == value int n = nums.size(); int ans = INT_MAX; for (int i = 0; i < n; ++i) { // Treat current i as j in (i_prev, i): // need reverse(nums[i_prev]) == nums[i] <=> nums[i] is in map auto it = lastIndexOfReversed.find(nums[i]); if (it != lastIndexOfReversed.end()) { ans = min(ans, i - it->second); // i > it->second always } // Now treat current index as the "i" of future pairs int r = reverseNum(nums[i]); lastIndexOfReversed[r] = i; // keep closest (largest) index } return ans == INT_MAX ? -1 : ans; } };

Idea in one line:
Scan from left to right, keep for each value v the last index where reverse(nums[index]) == v; when at position i, if nums[i] is already in the map, we’ve found a mirror pair ending at i, and we update the minimum distance.

問題

17644724147097665160860494920548.jpg17644724147097665160860494920548.jpg

Code in cpp

Python

python
print("test")

Python

python
import os, textwrap, itertools, math, statistics print(os.listdir('/mnt/data'))

Python

python
import PIL, sys, pkgutil, inspect, math, os, textwrap print(PIL.__version__)

Python

python
print(any(m.name=='pytesseract' for m in pkgutil.iter_modules()))

Python

python
import pytesseract, PIL.Image as Image img = Image.open('/mnt/data/17644724147097665160860494920548.jpg') text = pytesseract.image_to_string(img) print(text[:2000])

Python

python
import pytesseract from PIL import Image, ImageOps, ImageFilter, ImageEnhance img = Image.open('/mnt/data/17644724147097665160860494920548.jpg') img = img.rotate(90, expand=True) # crop region around text maybe center w,h = img.size crop = img.crop((0,h*0.15,w*0.85,h*0.95)) crop = ImageOps.autocontrast(crop) crop = crop.filter(ImageFilter.SHARPEN) text = pytesseract.image_to_string(crop) print(text)

Python

python
for angle in [90, 270]: print("ANGLE", angle) t = pytesseract.image_to_string(img.rotate(angle, expand=True)) print(t[:1500])

Python

python
img270 = img.rotate(270, expand=True) w,h = img270.size print(w,h) # crop roughly central text region crop = img270.crop((int(w*0.1), int(h*0.1), int(w*0.9), int(h*0.75))) crop = ImageOps.autocontrast(crop) crop = crop.filter(ImageFilter.SHARPEN) text = pytesseract.image_to_string(crop) print(text[:2000])

Python

python
text_full = pytesseract.image_to_string(img270) print(text_full)

Python

python
img = Image.open('/mnt/data/17644724147097665160860494920548.jpg') # try different crops on original orientation print(img.size) for i,box in enumerate([ (0,0,img.size[0], img.size[1]//2), (0,img.size[1]//4, img.size[0], 3*img.size[1]//4), (img.size[0]//4,0,3*img.size[0]//4, img.size[1]//2), ]): crop = img.crop(box) text = pytesseract.image_to_string(crop) print("CROP", i, "TEXT:\n", text[:1000], "\n---")

Python

python
img270 = img.rotate(270, expand=True) print(img270.size) for i,box in enumerate([ (0,0,img270.size[0], img270.size[1]//2), (0,img270.size[1]//4, img270.size[0], 3*img270.size[1]//4), (img270.size[0]//4,0,3*img270.size[0]//4, img270.size[1]//2), ]): crop = img270.crop(box) crop = ImageOps.autocontrast(crop) crop = crop.filter(ImageFilter.SHARPEN) text = pytesseract.image_to_string(crop) print("CROP", i, "TEXT:\n", text[:2000], "\n---")

Python

python
img90 = img.rotate(90, expand=True) print(img90.size) for i,box in enumerate([ (0,0,img90.size[0], img90.size[1]//2), (0,img90.size[1]//4, img90.size[0], 3*img90.size[1]//4), (img90.size[0]//4,0,3*img90.size[0]//4,img90.size[1]//2), ]): crop = img90.crop(box) crop = ImageOps.autocontrast(crop) crop = crop.filter(ImageFilter.SHARPEN) text = pytesseract.image_to_string(crop) print("CROP", i, "TEXT:\n", text[:2000], "\n---")

Python

python
from PIL import Image, ImageOps, ImageFilter img = Image.open('/mnt/data/17644724147097665160860494920548.jpg') img90 = img.rotate(90, expand=True) # Zoom in area where statement is presumably right side; We'll crop right half of image (since statement text is right side). w,h = img90.size print(w,h) crop = img90.crop((w//2, 0, w, h//2)) # top-right quadrant crop = crop.resize((crop.size[0]*2, crop.size[1]*2), Image.LANCZOS) crop = ImageOps.autocontrast(crop) crop = crop.filter(ImageFilter.SHARPEN) text = pytesseract.image_to_string(crop) print(text[:2000])

Python

python
crop = img90.crop((w//4, 0, w, h//2)) crop = crop.resize((crop.size[0]*2, crop.size[1]*2)) crop = ImageOps.autocontrast(crop) crop = crop.filter(ImageFilter.SHARPEN) text = pytesseract.image_to_string(crop) print(text[:2000])

Python

python
img180 = img.rotate(180, expand=True) text = pytesseract.image_to_string(img180) print(text[:2000])

Python

python
def brute(nums,k,l,r): kk=abs(k) # BFS min operations to equalize; but n small; we implement analytic method. sub=nums[l:r+1] # operations ±k; we reason: if difference of any pair not divisible by k -> -1 for i in range(len(sub)): for j in range(len(sub)): if (sub[i]-sub[j])%kk!=0: return -1 rem = ((sub[0]%kk)+kk)%kk if any(((x%kk)+kk)%kk!=rem for x in sub): return -1 # map to q qs=[(x-rem)//kk for x in sub] # compute best t integer; brute. best=None for t in range(min(qs)-5,max(qs)+6): cost=sum(abs(x-t) for x in qs) if best is None or cost<best: best=cost return best def analytic(nums,k,l,r): kk=abs(k) n=len(nums) # rem & q as described rem=[((x%kk)+kk)%kk

Python

python
# Let's implement persistent segtree as in C++ design, but in Python, # and test against analytic() which already matches brute(). class PST: def __init__(self, values): self.vals=sorted(set(values)) self.m=len(self.vals) self.seg=[(0,0,0,0)] # (l,r,cnt,sum) self.root=[0] def _new_node(self, base): self.seg.append(self.seg[base]) return len(self.seg)-1 def build_from_array(self, arr): # arr: list of q's pos=[self.vals.index(v)+1 for v in arr] # O(n^2) but fine for small test; C++ uses lower_bound for v,p in zip(arr,pos): newroot=self._update(self.root[-1],1,self.m,p,v) self.root.append(newroot) return pos def _update(self, prev, s,e,pos,val): cur=self._new_node(prev) l,r,cnt,sumv=self.seg[cur] if s==e: cnt+=1 sumv+=val self.seg[cur]=(l,r,cnt,sumv) return cur mid=(s+e)//2 if pos<=mid: newL=self._update(l,s,mid,pos,val) l=newL else: newR=self._update(r,mid+1,e,pos,val) r=newR cnt = self.seg[l][2] + self.seg[r][2] sumv = self.seg[l][3] + self.seg[r][3] self.seg[cur]=(l,r,cnt,sumv) return cur def kth(self, ru,rv,k): return self._kth(ru,rv,1,self.m,k) def _kth(self,u,v,s,e,k): if s==e: return s lu,ru=self.seg[u][0], self.seg[u][1] lv,rv_=self.seg[v][0], self.seg[v][1] leftCnt=self.seg[lu][2]-self.seg[lv][2] mid=(s+e)//2 if k<=leftCnt: return self._kth(lu,lv,s,mid,k) else: return self._kth(ru,rv_,mid+1,e,k-leftCnt) def range(self,ru,rv,L,R): return self._range(ru,rv,1,self.m,L,R) def _range(self,u,v,s,e,L,R): if R<s or e<L: return (0,0) lu,ru,cntu,sumu=self.seg[u] lv,rv_,cntv,sumv=self.seg[v] if L<=s and e<=R: return (cntu-cntv, sumu-sumv) mid=(s+e)//2 a=self._range(lu,lv,s,mid,L,R) b=self._range(ru,rv_,mid+1,e,L,R) return (a[0]+b[0], a[1]+b[1]) def pst_answer(nums,k,l,r): kk=abs(k) rem=[((x%kk)+kk)%kk for x in nums] q=[(x - ((x%kk)+kk)%kk)//kk for x in nums] n=len(nums) pst=PST(q) pst.build_from_array(q) # remainder test via transitions pref=[0]*n for i in range(1,n): pref[i]=pref[i-1]+(rem[i]!=rem[i-1]) if pref[r]-pref[l]>0: return -1 ru=pst.root[r+1]; rv=pst.root[l] length=r-l+1 kpos=(length+1)//2 idx=pst.kth(ru,rv,kpos) med=pst.vals[idx-1] cntL,sumL=pst.range(ru,rv,1,idx) cntT,sumT=pst.range(ru,rv,1,pst.m) cntR=cntT-cntL; sumR=sumT-sumL return med*cntL - sumL + sumR - med*cntR random.seed(1) for n in range(1,8): for _ in range(80): k=random.randint(1,10) nums=[random.randint(-20,20) for __ in range(n)] pst_helper=pst_answer for __ in range(8): l=random.randint(0,n-1) r=random.randint(l,n-1) b=brute(nums,k,l,r) a=pst_answer(nums,k,l,r) if a!=b: print("Mismatch!!!",n,k,nums,l,r,b,a) raise SystemExit print("Persistent segtree logic verified!")

Python

python
def solution(nums,k,queries): n=len(nums) ans=[0]*len(queries) if k==0: pref=[0]*n for i in range(1,n): pref[i]=pref[i-1]+(nums[i]!=nums[i-1]) for qi,(l,r) in enumerate(queries): if pref[r]-pref[l]>0: ans[qi]=-1 else: ans[qi]=0 return ans kk=abs(k) rem=[((x%kk)+kk)%kk for x in nums] q=[(x - ((x%kk)+kk)%kk)//kk for x in nums] # build transitions prefix pref=[0]*n for i in range(1,n): pref[i]=pref[i-1]+(rem[i]!=rem[i-1]) class PST: def __init__(self,values): self.vals=sorted(set(values)) self.m=len(self.vals) self.seg=[(0,0,0,0)] self.root=[0]*(n+1) def _clone(self,base): self.seg.append(self.seg[base]) return len(self.seg)-1 def update(self,prev,s,e,pos,val): cur=self._clone(prev) l,r,cnt,sumv=self.seg[cur] if s==e: cnt+=1; sumv+=val; self.seg[cur]=(l,r,cnt,sumv); return cur mid=(s+e)//2 if pos<=mid: newL=self.update(l,s,mid,pos,val); l=newL else: newR=self.update(r,mid+1,e,pos,val); r=newR cnt=self.seg[l][2]+self.seg[r][2] sumv=self.seg[l][3]+self.seg[r][3] self.seg[cur]=(l,r,cnt,sumv); return cur def kth(self,ru,rv,k): return self._kth(ru,rv,1,self.m,k) def _kth(self,u,v,s,e,k): if s==e: return s lu,ru=self.seg[u][0], self.seg[u][1] lv,rv_=self.seg[v][0], self.seg[v][1] leftCnt=self.seg[lu][2]-self.seg[lv][2] mid=(s+e)//2 if k<=leftCnt: return self._kth(lu,lv,s,mid,k) else: return self._kth(ru,rv_,mid+1,e,k-leftCnt) def range(self,ru,rv,L,R): return self._range(ru,rv,1,self.m,L,R) def _range(self,u,v,s,e,L,R): if R<s or e<L: return (0,0) lu,ru,cntu,sumu=self.seg[u] lv,rv_,cntv,sumv=self.seg[v] if L<=s and e<=R: return (cntu-cntv, sumu-sumv) mid=(s+e)//2 a=self._range(lu,lv,s,mid,L,R) b=self._range(ru,rv_,mid+1,e,L,R) return (a[0]+b[0], a[1]+b[1]) pst=PST(q) # coordinate positions vals=pst.vals pos=[vals.index(v)+1 for v in q] root=[0]*(n+1) for i in range(1,n+1): root[i]=pst.update(root[i-1],1,pst.m,pos[i-1],q[i-1]) pst.root=root for qi,(l,r) in enumerate(queries): if pref[r]-pref[l]>0: ans[qi]=-1; continue length=r-l+1 if length==1: ans[qi]=0; continue kpos=(length+1)//2 ru=root[r+1]; rv=root[l] idx=pst.kth(ru,rv,kpos); med=vals[idx-1] cntL,sumL=pst.range(ru,rv,1,idx) cntT,sumT=pst.range(ru,rv,1,pst.m) cntR=cntT-cntL; sumR=sumT-sumL res=med*cntL-sumL+sumR-med*cntR ans[qi]=res return ans print(solution([1,4,7],3,[(0,1),(0,2)]))

思考

Finalizing C++ code considerations

We need to carefully handle concurrency in the C++ implementation. For k==0, we only build the segment tree when necessary, and recursion depth will stay manageable at around 18 levels for 3.6 million nodes. We also need to adapt for LeetCode's 0-index queries and test with a known sample: nums=[1,4,7], k=3, queries=[[0,1], [0,2]].

Verifying median cost logic

The algorithm works for the sample, but I want to be cautious about potential corner cases. Let's double-check whether the operations cost aligns with the median cost. We transform values using steps of size k and want to minimize the total operation cost. For a set of values, the best choice of target t that minimizes total difference is the median, even for even numbers of elements. Therefore, the median minimizes our cost.

Converting algorithm to C++

The algorithm seems mathematically correct, so now it’s time to translate it into C++. I’ll focus on writing the code neatly and ensuring it follows good C++ practices while staying as efficient as possible. Let’s keep it clean and organized to avoid unnecessary complexity.

Converting pseudo code to C++

The algorithm’s pseudocode looks solid. I’m translating the logic into C++ now, while following the structure closely. I need to ensure the seg vector and structure for Node are properly handled, as well as maintaining the recursive nature of the segment tree operations. The minOperationsToEqualizeSubarrays function will wrap around the logic.

Planning out the C++ implementation

For the minOperationsToEqualizeSubarrays function, I’m breaking down the logic step by step. First, I create the seg vector and set up the roots. I need to manage how the values map and handle segment tree updates. Then, efficient handling of queries is in focus. Each query will be processed by calculating medians and minimal operations with the proper setup for k.

Handling edge cases for k and overflow

I'll need to account for specific edge cases like when k > 0 but the subarray length is 1 (no operations needed). There's also a risk of integer overflow with large values of k or n. To avoid this, I’ll carefully use long long for operations involving k and cast when needed, ensuring that overflow doesn't occur during calculations.

Ensuring no division by zero and handling k == 0

For the case where k == 0, I handle it early on to prevent doing unnecessary operations or dividing by zero. If k == 0, I can avoid working with modulo calculations or affecting the result at all. This early return helps safeguard against potential issues when k == 0, especially for operations.

Thought for 7m 8s

回答

Here’s a C++ solution for “Q4. Minimum Operations to Equalize Subarrays”.

Idea in short:

  • For a subarray [l, r] to be equalizable using ±k:
    • All elements must be congruent modulo k.
  • If they are, write each nums[i] = k * q[i] + rem (same rem).
    • Operations needed on nums[i] to reach target T = k * t + rem is |q[i] - t|.
    • So we just need to make the q[i]’s equal, and the minimum sum of |q[i] - t| is achieved at the median of q[i].
  • Thus, for each query:
    1. Check that all nums[l..r] have the same remainder modulo k.
      (Using a prefix array over “remainder changes”.)
    2. If yes, compute sum of absolute deviations from median of q[i] = (nums[i] - rem)/k in that range.
    3. To do this fast for many queries, use a persistent segment tree over the q[i] values:
      • supports k-th smallest (median) and range sum over [l, r] in O(log n).

Complexities:

  • Build: O(n log n)
  • Each query: O(log n)

cpp
#include <bits/stdc++.h> using namespace std; class Solution { public: struct Node { int l = 0, r = 0; // children indices in seg int cnt = 0; // how many numbers in this range long long sum = 0; // sum of numbers in this range }; vector<Node> seg; // persistent segment tree nodes int M; // number of distinct q-values // Build/update: return new root index based on previous root int update(int prev, int s, int e, int pos, long long val) { int cur = (int)seg.size(); seg.push_back(seg[prev]); // clone previous node if (s == e) { seg[cur].cnt += 1; seg[cur].sum += val; return cur; } int mid = (s + e) >> 1; if (pos <= mid) { int newL = update(seg[prev].l, s, mid, pos, val); seg[cur].l = newL; } else { int newR = update(seg[prev].r, mid + 1, e, pos, val); seg[cur].r = newR; } seg[cur].cnt = seg[seg[cur].l].cnt + seg[seg[cur].r].cnt; seg[cur].sum = seg[seg[cur].l].sum + seg[seg[cur].r].sum; return cur; } // k-th smallest value index in range using roots u (R) and v (L-1) int kth(int u, int v, int s, int e, int k) { if (s == e) return s; int lu = seg[u].l, ru = seg[u].r; int lv = seg[v].l, rv = seg[v].r; int leftCnt = seg[lu].cnt - seg[lv].cnt; int mid = (s + e) >> 1; if (k <= leftCnt) return kth(lu, lv, s, mid, k); return kth(ru, rv, mid + 1, e, k - leftCnt); } // (count, sum) of values whose indices are within [L, R] pair<long long,long long> rangeQuery(int u, int v, int s, int e, int L, int R) { if (R < s || e < L) return {0, 0}; if (L <= s && e <= R) { long long cnt = seg[u].cnt - seg[v].cnt; long long sum = seg[u].sum - seg[v].sum; return {cnt, sum}; } int mid = (s + e) >> 1; auto left = rangeQuery(seg[u].l, seg[v].l, s, mid, L, R); auto right = rangeQuery(seg[u].r, seg[v].r, mid + 1, e, L, R); return {left.first + right.first, left.second + right.second}; } vector<long long> minOperationsToEqualizeSubarrays(vector<int>& nums, int k, vector<vector<int>>& queries) { int n = (int)nums.size(); vector<long long> ans(queries.size()); // Special case k == 0: elements cannot change at all if (k == 0) { if (n == 0) return ans; vector<int> prefBad(n, 0); for (int i = 1; i < n; ++i) { prefBad[i] = prefBad[i - 1] + (nums[i] != nums[i - 1]); } for (int qi = 0; qi < (int)queries.size(); ++qi) { int l = queries[qi][0]; int r = queries[qi][1]; if (prefBad[r] - prefBad[l] > 0) ans[qi] = -1; else ans[qi] = 0; } return ans; } long long kk = llabs((long long)k); // make step positive // rem[i] = nums[i] mod k (normalized to [0, kk-1]) // q[i] = (nums[i] - rem[i]) / k vector<int> rem(n); vector<long long> q(n); for (int i = 0; i < n; ++i) { long long v = nums[i]; long long mod = v % kk; if (mod < 0) mod += kk; // normalize rem[i] = (int)mod; q[i] = (v - mod) / kk; } // prefix array that counts transitions of remainder // if any rem changes inside [l, r], impossible vector<int> prefBad(n, 0); for (int i = 1; i < n; ++i) { prefBad[i] = prefBad[i - 1] + (rem[i] != rem[i - 1]); } // Coordinate-compress q-values vector<long long> vals = q; sort(vals.begin(), vals.end()); vals.erase(unique(vals.begin(), vals.end()), vals.end()); M = (int)vals.size(); vector<int> pos(n); for (int i = 0; i < n; ++i) { pos[i] = int(lower_bound(vals.begin(), vals.end(), q[i]) - vals.begin()) + 1; // 1-based } // Build persistent segment tree over q seg.clear(); seg.reserve((n + 5) * 20); // rough upper bound seg.push_back(Node()); // node 0: empty vector<int> root(n + 1, 0); for (int i = 1; i <= n; ++i) { root[i] = update(root[i - 1], 1, M, pos[i - 1], q[i - 1]); } // Answer queries for (int qi = 0; qi < (int)queries.size(); ++qi) { int l = queries[qi][0]; int r = queries[qi][1]; // Check all nums[l..r] ≡ same (mod k) if (prefBad[r] - prefBad[l] > 0) { ans[qi] = -1; continue; } int len = r - l + 1; if (len == 1) { // single element already equal ans[qi] = 0; continue; } int kpos = (len + 1) / 2; // position of lower median int rootR = root[r + 1]; int rootL = root[l]; // find index of median in compressed coords int idxMed = kth(rootR, rootL, 1, M, kpos); long long medVal = vals[idxMed - 1]; // sum & count of elements <= median auto left = rangeQuery(rootR, rootL, 1, M, 1, idxMed); long long cntLeft = left.first; long long sumLeft = left.second; // total sum & count in [l, r] auto whole = rangeQuery(rootR, rootL, 1, M, 1, M); long long cntTotal = whole.first; // should equal len long long sumTotal = whole.second; long long cntRight = cntTotal - cntLeft; long long sumRight = sumTotal - sumLeft; long long cost = medVal * cntLeft - sumLeft + sumRight - medVal * cntRight; ans[qi] = cost; } return ans; } };

You can drop this straight into the LeetCode editor and just adjust the function name/signature if their stub is slightly different.

分享這個問答