HackerRank Nikita and the Game代码段错误排查求助(无调试器)
Let's break down why your code is hitting a segmentation fault, and walk through how to fix it—plus strategies for debugging such issues in competitive programming when you can't access test cases or debuggers.
First, the Root Cause of Your Segmentation Fault
Your code runs into an infinite recursion loop that causes a stack overflow, which triggers the segmentation fault. Here's exactly how that happens:
Invalid Split Allowing Empty Subarrays:
TheisPossiblefunction is designed to find a split point where the left and right sums are equal, but it allows splitting into a non-empty left subarray and an empty right subarray (whenmid == end). For example, if you have a single element0:pre_sumbecomes[0, 0]calcAnsis called withstart=1,end=1isPossiblechecksmid=1, calculates left sum aspre_sum[1]-pre_sum[0] = 0, right sum aspre_sum[1]-pre_sum[1] = 0- It returns
idx=1, socalcAnsrecursively calls itself withstart=1,end=1(the same interval) - This loop repeats infinitely until the program runs out of stack space, causing a segmentation fault.
Missing Termination Condition for Small Intervals:
YourcalcAnsfunction doesn't check if the interval is too small to split (length 1 or 0). Even if you fix the split logic, without this check, you might still end up with unnecessary recursive calls.
Fixed Code
Here's the corrected version of your code with explanations of the changes:
#include <bits/stdc++.h> #define lld long long using namespace std; lld isPossible(vector<lld>& pre_sum, lld start, lld end) { lld low = start - 1; lld high = end; // We only look for splits that create TWO NON-EMPTY subarrays, so mid must be < end while (start < end) { lld mid = (start + end) / 2; lld left_sum = pre_sum[mid] - pre_sum[low]; lld right_sum = pre_sum[high] - pre_sum[mid]; if (left_sum == right_sum) { return mid; } else if (left_sum < right_sum) { start = mid + 1; } else { end = mid; } } // No valid split found (or interval is too small to split) return -1; } lld calcAns(vector<lld>& pre_sum, lld start, lld end) { // Terminate early if interval can't be split into two non-empty parts if (start >= end) { return 0; } lld idx = isPossible(pre_sum, start, end); if (idx == -1) { return 0; } // Recurse on both valid subarrays return 1 + max(calcAns(pre_sum, start, idx), calcAns(pre_sum, idx + 1, end)); } lld arraySplitting(vector<lld> arr) { vector<lld> pre_sum(arr.size() + 1); pre_sum[0] = 0; for (lld i = 0; i < arr.size(); i++) { pre_sum[i + 1] = pre_sum[i] + arr[i]; } return calcAns(pre_sum, 1, pre_sum.size() - 1); } int main() { lld t; cin >> t; for (lld t_itr = 0; t_itr < t; t_itr++) { lld arr_count; cin >> arr_count; vector<lld> arr(arr_count); for (lld arr_itr = 0; arr_itr < arr_count; arr_itr++) { lld arr_item; cin >> arr_item; arr[arr_itr] = arr_item; } cout << arraySplitting(arr) << "\n"; } return 0; }
Key changes made:
- Updated
isPossibleto only search for splits wheremid < end(ensuring both subarrays are non-empty) - Added an early termination condition in
calcAnsfor intervals that can't be split (start >= end) - Fixed the binary search logic to avoid skipping potential split points (changed
end = mid-1toend = midwhen left sum is larger)
Strategies for Debugging Segmentation Faults in Competitive Programming
When you can't access test cases or debuggers, use these tactics to narrow down the issue:
Test Extreme Edge Cases Manually:
- Single-element arrays (especially with
0) - All-zero arrays
- Large arrays (to check for stack overflow from deep recursion)
- Arrays with maximum/minimum possible values (to check for integer overflow)
- Single-element arrays (especially with
Validate Recursion Termination:
- Ensure every recursive path has a clear exit condition. For example, in your code, adding
if (start >= end) return 0stops infinite loops on small intervals. - Print recursive parameters (like
startandend) to see if you're repeating the same interval infinitely.
- Ensure every recursive path has a clear exit condition. For example, in your code, adding
Check Array Index Bounds:
- Verify all array accesses are within valid ranges. For example,
pre_sumhas indices from0toarr.size(), so any access outside this range will cause a segfault.
- Verify all array accesses are within valid ranges. For example,
Replace Recursion with Iteration (If Needed):
- If you suspect stack overflow from deep recursion, rewrite the recursive logic using a stack/queue data structure to simulate recursion iteratively. This avoids hitting stack limits.
Check for Integer Overflow:
- Even if it doesn't cause a segfault directly, overflow can lead to incorrect values that trigger invalid array accesses or wrong split decisions. Use larger data types (like
long long) if needed.
- Even if it doesn't cause a segfault directly, overflow can lead to incorrect values that trigger invalid array accesses or wrong split decisions. Use larger data types (like
内容的提问来源于stack exchange,提问作者user13145713

