Skip to content

Commit 8f6a87b

Browse files
committed
Search in rotated sorted array II
1 parent 2d8824b commit 8f6a87b

File tree

2 files changed

+364
-0
lines changed

2 files changed

+364
-0
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// 81. Search in rotated sorted array II
2+
// Topics: 'Array', 'Binary Search'
3+
4+
// There is an integer array nums sorted in non-decreasing order (not necessarily with distinct values).
5+
6+
// Before being passed to your function, nums is rotated at an unknown pivot index k (0 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,4,4,5,6,6,7] might be rotated at pivot index 5 and become [4,5,6,6,7,0,1,2,4,4].
7+
8+
// Given the array nums after the rotation and an integer target, return true if target is in nums, or false if it is not in nums.
9+
10+
// You must decrease the overall operation steps as much as possible.
11+
12+
// Example 1:
13+
14+
// Input: nums = [2,5,6,0,0,1,2], target = 0
15+
// Output: true
16+
17+
// Example 2:
18+
19+
// Input: nums = [2,5,6,0,0,1,2], target = 3
20+
// Output: false
21+
22+
// Constraints:
23+
24+
// 1 <= nums.length <= 5000
25+
// -104 <= nums[i] <= 104
26+
// nums is guaranteed to be rotated at some pivot.
27+
// -104 <= target <= 104
28+
29+
package searchinrotatedsortedarrayii
30+
31+
func search(nums []int, target int) bool {
32+
L, R := 0, len(nums)-1
33+
for L <= R {
34+
L, R = skipDuplicates(nums, L, R)
35+
36+
m := (L + R) / 2
37+
if target == nums[m] {
38+
return true
39+
}
40+
if nums[L] <= nums[m] {
41+
if target < nums[m] && target >= nums[L] {
42+
//sorted
43+
R = m - 1
44+
} else {
45+
L = m + 1
46+
}
47+
} else {
48+
if target > nums[m] && target <= nums[R] {
49+
//sorted
50+
L = m + 1
51+
} else {
52+
R = m - 1
53+
}
54+
}
55+
}
56+
return false
57+
}
58+
59+
func skipDuplicates(nums []int, L, R int) (int, int) {
60+
for L < R {
61+
if nums[L] == nums[L+1] {
62+
L++
63+
continue
64+
}
65+
if nums[R] == nums[R-1] {
66+
R--
67+
continue
68+
}
69+
if nums[R] == nums[L] {
70+
R--
71+
continue
72+
}
73+
break
74+
}
75+
return L, R
76+
}
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
package searchinrotatedsortedarrayii
2+
3+
import "testing"
4+
5+
func TestSearch(t *testing.T) {
6+
tests := []struct {
7+
name string
8+
nums []int
9+
target int
10+
want bool
11+
}{
12+
// Basic examples from problem
13+
{
14+
name: "Example 1: target exists",
15+
nums: []int{2, 5, 6, 0, 0, 1, 2},
16+
target: 0,
17+
want: true,
18+
},
19+
{
20+
name: "Example 2: target doesn't exist",
21+
nums: []int{2, 5, 6, 0, 0, 1, 2},
22+
target: 3,
23+
want: false,
24+
},
25+
// Single element
26+
{
27+
name: "Single element - found",
28+
nums: []int{1},
29+
target: 1,
30+
want: true,
31+
},
32+
{
33+
name: "Single element - not found",
34+
nums: []int{1},
35+
target: 0,
36+
want: false,
37+
},
38+
// Two elements
39+
{
40+
name: "Two elements - first",
41+
nums: []int{1, 3},
42+
target: 1,
43+
want: true,
44+
},
45+
{
46+
name: "Two elements - second",
47+
nums: []int{1, 3},
48+
target: 3,
49+
want: true,
50+
},
51+
{
52+
name: "Two elements - not found",
53+
nums: []int{1, 3},
54+
target: 2,
55+
want: false,
56+
},
57+
// All duplicates
58+
{
59+
name: "All same elements - target exists",
60+
nums: []int{1, 1, 1, 1, 1},
61+
target: 1,
62+
want: true,
63+
},
64+
{
65+
name: "All same elements - target doesn't exist",
66+
nums: []int{1, 1, 1, 1, 1},
67+
target: 2,
68+
want: false,
69+
},
70+
// Duplicates with rotation
71+
{
72+
name: "Duplicates at boundaries",
73+
nums: []int{1, 1, 1, 2, 1, 1, 1},
74+
target: 2,
75+
want: true,
76+
},
77+
{
78+
name: "Many duplicates - target at beginning",
79+
nums: []int{2, 2, 2, 3, 4, 2},
80+
target: 3,
81+
want: true,
82+
},
83+
{
84+
name: "Many duplicates - target at end",
85+
nums: []int{3, 1, 2, 2, 2, 2},
86+
target: 1,
87+
want: true,
88+
},
89+
// No rotation (already sorted)
90+
{
91+
name: "No rotation - sorted array",
92+
nums: []int{1, 2, 3, 4, 5},
93+
target: 3,
94+
want: true,
95+
},
96+
{
97+
name: "No rotation - target not found",
98+
nums: []int{1, 2, 3, 4, 5},
99+
target: 6,
100+
want: false,
101+
},
102+
// Heavy rotation
103+
{
104+
name: "Rotated at last position",
105+
nums: []int{5, 1, 2, 3, 4},
106+
target: 1,
107+
want: true,
108+
},
109+
{
110+
name: "Rotated in middle",
111+
nums: []int{4, 5, 6, 7, 0, 1, 2},
112+
target: 0,
113+
want: true,
114+
},
115+
// Edge cases with duplicates
116+
{
117+
name: "Target equals boundary duplicates",
118+
nums: []int{1, 3, 1, 1, 1},
119+
target: 1,
120+
want: true,
121+
},
122+
{
123+
name: "Two distinct values with duplicates",
124+
nums: []int{1, 1, 3, 1},
125+
target: 3,
126+
want: true,
127+
},
128+
// Negative numbers
129+
{
130+
name: "Negative numbers - found",
131+
nums: []int{-5, -3, -1, 0, 2, 4},
132+
target: -3,
133+
want: true,
134+
},
135+
{
136+
name: "Negative numbers - not found",
137+
nums: []int{-5, -3, -1, 0, 2, 4},
138+
target: -2,
139+
want: false,
140+
},
141+
{
142+
name: "Mixed negative and positive",
143+
nums: []int{3, 4, 5, -5, -3, -1, 0, 1},
144+
target: -3,
145+
want: true,
146+
},
147+
// Target at different positions
148+
{
149+
name: "Target at beginning",
150+
nums: []int{3, 4, 5, 1, 2},
151+
target: 3,
152+
want: true,
153+
},
154+
{
155+
name: "Target at end",
156+
nums: []int{3, 4, 5, 1, 2},
157+
target: 2,
158+
want: true,
159+
},
160+
{
161+
name: "Target in middle",
162+
nums: []int{4, 5, 6, 7, 0, 1, 2},
163+
target: 6,
164+
want: true,
165+
},
166+
// Complex duplicate patterns
167+
{
168+
name: "Duplicates everywhere",
169+
nums: []int{2, 2, 2, 3, 2, 2, 2},
170+
target: 3,
171+
want: true,
172+
},
173+
{
174+
name: "Duplicates everywhere - not found",
175+
nums: []int{2, 2, 2, 3, 2, 2, 2},
176+
target: 4,
177+
want: false,
178+
},
179+
// Boundary values
180+
{
181+
name: "Max constraint values",
182+
nums: []int{10000, -10000, 0},
183+
target: -10000,
184+
want: true,
185+
},
186+
{
187+
name: "Zero in array",
188+
nums: []int{0, 0, 1, 2, 0},
189+
target: 0,
190+
want: true,
191+
},
192+
}
193+
194+
for _, tt := range tests {
195+
t.Run(tt.name, func(t *testing.T) {
196+
got := search(tt.nums, tt.target)
197+
if got != tt.want {
198+
t.Errorf("search(%v, %d) = %v, want %v", tt.nums, tt.target, got, tt.want)
199+
}
200+
})
201+
}
202+
}
203+
204+
func TestSkipDuplicates(t *testing.T) {
205+
tests := []struct {
206+
name string
207+
nums []int
208+
L int
209+
R int
210+
wantL int
211+
wantR int
212+
}{
213+
{
214+
name: "No duplicates",
215+
nums: []int{1, 2, 3, 4, 5},
216+
L: 0,
217+
R: 4,
218+
wantL: 0,
219+
wantR: 4,
220+
},
221+
{
222+
name: "Duplicates at left",
223+
nums: []int{1, 1, 1, 2, 3},
224+
L: 0,
225+
R: 4,
226+
wantL: 2,
227+
wantR: 4,
228+
},
229+
{
230+
name: "Duplicates at right",
231+
nums: []int{1, 2, 3, 3, 3},
232+
L: 0,
233+
R: 4,
234+
wantL: 0,
235+
wantR: 2,
236+
},
237+
{
238+
name: "Duplicates at both ends",
239+
nums: []int{1, 1, 2, 1, 1},
240+
L: 0,
241+
R: 4,
242+
wantL: 1,
243+
wantR: 2,
244+
},
245+
{
246+
name: "All same elements",
247+
nums: []int{1, 1, 1, 1, 1},
248+
L: 0,
249+
R: 4,
250+
wantL: 4,
251+
wantR: 4,
252+
},
253+
{
254+
name: "Two elements - same",
255+
nums: []int{1, 1},
256+
L: 0,
257+
R: 1,
258+
wantL: 1,
259+
wantR: 1,
260+
},
261+
{
262+
name: "Two elements - different",
263+
nums: []int{1, 2},
264+
L: 0,
265+
R: 1,
266+
wantL: 0,
267+
wantR: 1,
268+
},
269+
{
270+
name: "Complex pattern",
271+
nums: []int{1, 1, 1, 2, 1, 1, 1},
272+
L: 0,
273+
R: 6,
274+
wantL: 2,
275+
wantR: 3,
276+
},
277+
}
278+
279+
for _, tt := range tests {
280+
t.Run(tt.name, func(t *testing.T) {
281+
gotL, gotR := skipDuplicates(tt.nums, tt.L, tt.R)
282+
if gotL != tt.wantL || gotR != tt.wantR {
283+
t.Errorf("skipDuplicates(%v, %d, %d) = (%d, %d), want (%d, %d)",
284+
tt.nums, tt.L, tt.R, gotL, gotR, tt.wantL, tt.wantR)
285+
}
286+
})
287+
}
288+
}

0 commit comments

Comments
 (0)