Quickselect implementation not working - java

I am trying to write code to determine the n smallest item in an array. It's sad that I am struggling with this. Based on the algorithm from my college textbook from back in the day, this looks to be correct. However, obviously I am doing something wrong as it gives me a stack overflow exception.
My approach is:
Set the pivot to be at start + (end-start) / 2 (rather than start+end/2 to prevent overflow)
Use the integer at this location to be the pivot that I compare everything to
Iterate and swap everything around this pivot so things are sorted (sorted relative to the pivot)
If n == pivot, then I think I am done
Otherwise, if I want the 4 smallest element and pivot is 3, for example, then I need to look on the right side (or left side if I wanted the 2nd smallest element).
-
public static void main(String[] args) {
int[] elements = {30, 50, 20, 10};
quickSelect(elements, 3);
}
private static int quickSelect(int[] elements2, int k) {
return quickSelect(elements2, k, 0, elements2.length - 1);
}
private static int quickSelect(int[] elements, int k, int start, int end) {
int pivot = start + (end - start) / 2;
int midpoint = elements[pivot];
int i = start, j = end;
while (i < j) {
while (elements[i] < midpoint) {
i++;
}
while (elements[j] > midpoint) {
j--;
}
if (i <= j) {
int temp = elements[i];
elements[i] = elements[j];
elements[j] = temp;
i++;
j--;
}
}
// Guessing something's wrong here
if (k == pivot) {
System.out.println(elements[pivot]);
return pivot;
} else if (k < pivot) {
return quickSelect(elements, k, start, pivot - 1);
} else {
return quickSelect(elements, k, pivot + 1, end);
}
}
Edit: Please at least bother commenting why if you're going to downvote a valid question.

This won't fix the issue, but there are several problems with your code :
If you do not check for i < end and j > start in your whiles, you may run into out of bounds in some cases
You choose your pivot to be in the middle of the subarray, but nothing proves that it won't change position during partitioning. Then, you check for k == pivot with the old pivot position, which obviously won't work
Hope this helps a bit.

Alright so the first thing I did was rework how I get my pivot/partition point. The shortcoming, as T. Claverie pointed out, is that the pivot I am using isn't technically the pivot since the element's position changes during the partitioning phase.
I actually rewrote the partitioning code into its own method as below. This is slightly different.
I choose the first element (at start) as the pivot, and I create a "section" in front of this with items less than this pivot. Then, I swap the pivot's value with the last item in the section of values < the pivot. I return that final index as the point of the pivot.
This can be cleaned up more (create separate swap method).
private static int getPivot(int[] elements, int start, int end) {
int pivot = start;
int lessThan = start;
for (int i = start; i <= end; i++) {
int currentElement = elements[i];
if (currentElement < elements[pivot]) {
lessThan++;
int tmp = elements[lessThan];
elements[lessThan] = elements[i];
elements[i] = tmp;
}
}
int tmp = elements[lessThan];
elements[lessThan] = elements[pivot];
elements[pivot] = tmp;
return lessThan;
}
Here's the routine that's calls this:
private static int quickSelect(int[] elements, int k, int start, int end) {
int pivot = getPivot(elements, start, end);
if (k == (pivot - start + 1)) {
System.out.println(elements[pivot]);
return pivot;
} else if (k < (pivot - start + 1)) {
return quickSelect(elements, k, start, pivot - 1);
} else {
return quickSelect(elements, k - (pivot - start + 1), pivot + 1, end);
}
}

Related

QuickSort not working, think swap is the issue, Disclaimer I must use the quicksort method provided to me

try {
for (i = 0; i < data.length; i++) {
working[i] = data[i];
}
FileWriter fw3 = new FileWriter("quicksort.dat");
long startTime3 = System.nanoTime();
quickSort(working,0, working.length - 1);
long endTime3 = System.nanoTime();
long totalTime3 = endTime3 - startTime3;
System.out.println("The time to complete the quick sort was :" + totalTime3 + " nano seconds");
for (i = 0; i < working.length; i++) {
fw3.write(Integer.toString(working[i]) + "\n");
}
System.out.println("The file has been sorted by quick sort and output to quicksort.dat \n");
fw3.close();
} catch (IOException e) {
System.out.println(e);
}
static void quickSort(int data[], int left, int right) {
int i, j;
int partition;
if (right > left) {
partition = data[right];
i = left - 1;
j = right;
for (;;) {
while (data[++i] < partition);
while (data[--j] > partition);
if (i >= j) {
break;
}
swap(data[i], data[j]);
swap(data[i], data[right]);
quickSort(data, left, i - 1);
quickSort(data, i + 1, right);
}
}
}
static void swap(int left, int right) {
int array[] = new int[19];
int temp = array[left];
array[left] = array[right];
array[right]=temp;
This is just snippets of the code whole program is other sorts. I get an out bounds error every time it gets down to the quicksort function. I use 19 as my array because that is how big the file is I have tried 20 to see if it fixes it with no luck.
EDIT: I provided updated code down below to reflect changes that were made I still get an out of bounds error.
static void quickSort(int data[], int left, int right) {
int i, j;
int partition;
if (right > left) {
partition = data[right];
i = left - 1;
j = right;
for (;;) {
while (data[++i] < partition);
while (data[--j] > partition);
if (i >= j) {
break;
}
swap(data, i, j);
swap(data, i, right);
quickSort(data, left, i - 1);
quickSort(data, i + 1, right);
}
}
}
static void swap(int array[], int left, int right) {
int temp = array[left];
array[left] = array[right];
array[right] = temp;
}
You have declared swap as :
void swap(int left, int right)
So the arguments are the indexes into the array.
However, you call it with :
swap(data[i], data[j]);
So you are passing the VALUES in the array.
Try changing the call to :
swap(i, j);
EDIT TO ADD:
It must be pointed out that the issue above is just ONE issue with the sorting algorithm presented. Another problem is that the swap algorithm does not actually swap anything. It creates a local array variable array, operates on that and then returns (so discarding that local variable).
If your assignment is to output a sorted list of numbers, and that the numbers must be sorted using the sorting code presented - then that assignment is impossible because the sorting code presented is hopelessly flawed as a sorting algorithm; it does NOT sort (as you have found yourself), and has blatant severe issues compared to a correct implementation of quicksort (eg, you can compare to the answer here : https://stackoverflow.com/a/63811974/681444 )
EDIT TO ADD FOLLOWING REVISED CODE:
The revised sorting code is STILL hopelessly busted. It is not a correct implementation of QuickSort, and still does not sort correctly.
For example, I tried running it with the final element being the largest :
int data[] = {23, 8, 19, 35, 2, 12, 7, 64 };
Result : No sorting - the method hit the if (i >= j) {break;} with i==7 and j==6 straight off and so did nothing.
By contrast, the method in the answer I linked to above sorted correctly, so you can compare the method you have been given against that - or against other established articles (eg, do an internet search for java quicksort, there are plenty around)
As already noted by 'racraman', the sort definitely requires fixing.
Try re-implementing the sort function with the following method signature.
void sort(int[] arr, int leftIndex, int rightIndex) {
// swap code goes here
}

Arrays.binarySearch next index [duplicate]

This question already has answers here:
Finding multiple entries with binary search
(15 answers)
Closed 3 years ago.
I've been tasked with creating a method that will print all the indices where value x is found in a sorted array.
I understand that if we just scanned through the array from 0 to N (length of array) it would have a running time of O(n) worst case. Since the array that will be passed into the method will be sorted, I'm assuming that I can take advantage of using a Binary Search since this will be O(log n). However, this only works if the array has unique values. Since the Binary Search will finish after the first "find" of a particular value. I was thinking of doing a Binary Search for finding x in the sorted array, and then checking all values before and after this index, but then if the array contained all x values, it doesn't seem like it would be that much better.
I guess what I'm asking is, is there a better way to find all the indices for a particular value in a sorted array that is better than O(n)?
public void PrintIndicesForValue42(int[] sortedArrayOfInts)
{
// search through the sortedArrayOfInts
// print all indices where we find the number 42.
}
Ex: sortedArray = { 1, 13, 42, 42, 42, 77, 78 } would print: "42 was found at Indices: 2, 3, 4"
You will get the result in O(lg n)
public static void PrintIndicesForValue(int[] numbers, int target) {
if (numbers == null)
return;
int low = 0, high = numbers.length - 1;
// get the start index of target number
int startIndex = -1;
while (low <= high) {
int mid = (high - low) / 2 + low;
if (numbers[mid] > target) {
high = mid - 1;
} else if (numbers[mid] == target) {
startIndex = mid;
high = mid - 1;
} else
low = mid + 1;
}
// get the end index of target number
int endIndex = -1;
low = 0;
high = numbers.length - 1;
while (low <= high) {
int mid = (high - low) / 2 + low;
if (numbers[mid] > target) {
high = mid - 1;
} else if (numbers[mid] == target) {
endIndex = mid;
low = mid + 1;
} else
low = mid + 1;
}
if (startIndex != -1 && endIndex != -1){
for(int i=0; i+startIndex<=endIndex;i++){
if(i>0)
System.out.print(',');
System.out.print(i+startIndex);
}
}
}
Well, if you actually do have a sorted array, you can do a binary search until you find one of the indexes you're looking for, and from there, the rest should be easy to find since they're all next to each-other.
once you've found your first one, than you go find all the instances before it, and then all the instances after it.
Using that method you should get roughly O(lg(n)+k) where k is the number of occurrences of the value that you're searching for.
EDIT:
And, No, you will never be able to access all k values in anything less than O(k) time.
Second edit: so that I can feel as though I'm actually contributing something useful:
Instead of just searching for the first and last occurrences of X than you can do a binary search for the first occurence and a binary search for the last occurrence. which will result in O(lg(n)) total. once you've done that, you'll know that all the between indexes also contain X(assuming that it's sorted)
You can do this by searching checking if the value is equal to x , AND checking if the value to the left(or right depending on whether you're looking for the first occurrence or the last occurrence) is equal to x.
public void PrintIndicesForValue42(int[] sortedArrayOfInts) {
int index_occurrence_of_42 = left = right = binarySearch(sortedArrayOfInts, 42);
while (left - 1 >= 0) {
if (sortedArrayOfInts[left-1] == 42)
left--;
}
while (right + 1 < sortedArrayOfInts.length) {
if (sortedArrayOfInts[right+1] == 42)
right++;
}
System.out.println("Indices are from: " + left + " to " + right);
}
This would run in O(log(n) + #occurrences)
Read and understand the code. It's simple enough.
Below is the java code which returns the range for which the search-key is spread in the given sorted array:
public static int doBinarySearchRec(int[] array, int start, int end, int n) {
if (start > end) {
return -1;
}
int mid = start + (end - start) / 2;
if (n == array[mid]) {
return mid;
} else if (n < array[mid]) {
return doBinarySearchRec(array, start, mid - 1, n);
} else {
return doBinarySearchRec(array, mid + 1, end, n);
}
}
/**
* Given a sorted array with duplicates and a number, find the range in the
* form of (startIndex, endIndex) of that number. For example,
*
* find_range({0 2 3 3 3 10 10}, 3) should return (2,4). find_range({0 2 3 3
* 3 10 10}, 6) should return (-1,-1). The array and the number of
* duplicates can be large.
*
*/
public static int[] binarySearchArrayWithDup(int[] array, int n) {
if (null == array) {
return null;
}
int firstMatch = doBinarySearchRec(array, 0, array.length - 1, n);
int[] resultArray = { -1, -1 };
if (firstMatch == -1) {
return resultArray;
}
int leftMost = firstMatch;
int rightMost = firstMatch;
for (int result = doBinarySearchRec(array, 0, leftMost - 1, n); result != -1;) {
leftMost = result;
result = doBinarySearchRec(array, 0, leftMost - 1, n);
}
for (int result = doBinarySearchRec(array, rightMost + 1, array.length - 1, n); result != -1;) {
rightMost = result;
result = doBinarySearchRec(array, rightMost + 1, array.length - 1, n);
}
resultArray[0] = leftMost;
resultArray[1] = rightMost;
return resultArray;
}
Another result for log(n) binary search for leftmost target and rightmost target. This is in C++, but I think it is quite readable.
The idea is that we always end up when left = right + 1. So, to find leftmost target, if we can move right to rightmost number which is less than target, left will be at the leftmost target.
For leftmost target:
int binary_search(vector<int>& nums, int target){
int n = nums.size();
int left = 0, right = n - 1;
// carry right to the greatest number which is less than target.
while(left <= right){
int mid = (left + right) / 2;
if(nums[mid] < target)
left = mid + 1;
else
right = mid - 1;
}
// when we are here, right is at the index of greatest number
// which is less than target and since left is at the next,
// it is at the first target's index
return left;
}
For the rightmost target, the idea is very similar:
int binary_search(vector<int>& nums, int target){
while(left <= right){
int mid = (left + right) / 2;
// carry left to the smallest number which is greater than target.
if(nums[mid] <= target)
left = mid + 1;
else
right = mid - 1;
}
// when we are here, left is at the index of smallest number
// which is greater than target and since right is at the next,
// it is at the first target's index
return right;
}
I came up with the solution using binary search, only thing is to do the binary search on both the sides if the match is found.
public static void main(String[] args) {
int a[] ={1,2,2,5,5,6,8,9,10};
System.out.println(2+" IS AVAILABLE AT = "+findDuplicateOfN(a, 0, a.length-1, 2));
System.out.println(5+" IS AVAILABLE AT = "+findDuplicateOfN(a, 0, a.length-1, 5));
int a1[] ={2,2,2,2,2,2,2,2,2};
System.out.println(2+" IS AVAILABLE AT = "+findDuplicateOfN(a1, 0, a1.length-1, 2));
int a2[] ={1,2,3,4,5,6,7,8,9};
System.out.println(10+" IS AVAILABLE AT = "+findDuplicateOfN(a2, 0, a2.length-1, 10));
}
public static String findDuplicateOfN(int[] a, int l, int h, int x){
if(l>h){
return "";
}
int m = (h-l)/2+l;
if(a[m] == x){
String matchedIndexs = ""+m;
matchedIndexs = matchedIndexs+findDuplicateOfN(a, l, m-1, x);
matchedIndexs = matchedIndexs+findDuplicateOfN(a, m+1, h, x);
return matchedIndexs;
}else if(a[m]>x){
return findDuplicateOfN(a, l, m-1, x);
}else{
return findDuplicateOfN(a, m+1, h, x);
}
}
2 IS AVAILABLE AT = 12
5 IS AVAILABLE AT = 43
2 IS AVAILABLE AT = 410236578
10 IS AVAILABLE AT =
I think this is still providing the results in O(logn) complexity.
A Hashmap might work, if you're not required to use a binary search.
Create a HashMap where the Key is the value itself, and then value is an array of indices where that value is in the array. Loop through your array, updating each array in the HashMap for each value.
Lookup time for the indices for each value will be ~ O(1), and creating the map itself will be ~ O(n).
Find_Key(int arr[], int size, int key){
int begin = 0;
int end = size - 1;
int mid = end / 2;
int res = INT_MIN;
while (begin != mid)
{
if (arr[mid] < key)
begin = mid;
else
{
end = mid;
if(arr[mid] == key)
res = mid;
}
mid = (end + begin )/2;
}
return res;
}
Assuming the array of ints is in ascending sorted order; Returns the index of the first index of key occurrence or INT_MIN. Runs in O(lg n).
It is using Modified Binary Search. It will be O(LogN). Space complexity will be O(1).
We are calling BinarySearchModified two times. One for finding start index of element and another for finding end index of element.
private static int BinarySearchModified(int[] input, double toSearch)
{
int start = 0;
int end = input.Length - 1;
while (start <= end)
{
int mid = start + (end - start)/2;
if (toSearch < input[mid]) end = mid - 1;
else start = mid + 1;
}
return start;
}
public static Result GetRange(int[] input, int toSearch)
{
if (input == null) return new Result(-1, -1);
int low = BinarySearchModified(input, toSearch - 0.5);
if ((low >= input.Length) || (input[low] != toSearch)) return new Result(-1, -1);
int high = BinarySearchModified(input, toSearch + 0.5);
return new Result(low, high - 1);
}
public struct Result
{
public int LowIndex;
public int HighIndex;
public Result(int low, int high)
{
LowIndex = low;
HighIndex = high;
}
}
public void printCopies(int[] array)
{
HashMap<Integer, Integer> memberMap = new HashMap<Integer, Integer>();
for(int i = 0; i < array.size; i++)
if(!memberMap.contains(array[i]))
memberMap.put(array[i], 1);
else
{
int temp = memberMap.get(array[i]); //get the number of occurances
memberMap.put(array[i], ++temp); //increment his occurance
}
//check keys which occured more than once
//dump them in a ArrayList
//return this ArrayList
}
Alternatevely, instead of counting the number of occurances, you can put their indices in a arraylist and put that in the map instead of the count.
HashMap<Integer, ArrayList<Integer>>
//the integer is the value, the arraylist a list of their indices
public void printCopies(int[] array)
{
HashMap<Integer, ArrayList<Integer>> memberMap = new HashMap<Integer, ArrayList<Integer>>();
for(int i = 0; i < array.size; i++)
if(!memberMap.contains(array[i]))
{
ArrayList temp = new ArrayList();
temp.add(i);
memberMap.put(array[i], temp);
}
else
{
ArrayList temp = memberMap.get(array[i]); //get the lsit of indices
temp.add(i);
memberMap.put(array[i], temp); //update the index list
}
//check keys which return lists with length > 1
//handle the result any way you want
}
heh, i guess this will have to be posted.
int predefinedDuplicate = //value here;
int index = Arrays.binarySearch(array, predefinedDuplicate);
int leftIndex, rightIndex;
//search left
for(leftIndex = index; array[leftIndex] == array[index]; leftIndex--); //let it run thru it
//leftIndex is now the first different element to the left of this duplicate number string
for(rightIndex = index; array[rightIndex] == array[index]; rightIndex++); //let it run thru it
//right index contains the first different element to the right of the string
//you can arraycopy this [leftIndex+1, rightIndex-1] string or just print it
for(int i = leftIndex+1; i<rightIndex; i++)
System.out.println(array[i] + "\t");

Quick-sort in ascending order

I am trying to pass my implementation of the Quicksort through a tester; however, I get Array Index Out Of Bounds exception of -1 on the commended line
public void quickSort(ArrayList<String> data, int firstIndex,
int numberToSort) {
if (data.size() < 16) {
insertionSort(data, firstIndex, numberToSort);
} else {
int index = partition(data, firstIndex, numberToSort);
if (firstIndex < index - 1)
quickSort(data, firstIndex, index - 1);
if (numberToSort > index)
quickSort(data, index, numberToSort);
}
}
#Override
public int partition(ArrayList<String> data, int firstIndex,
int numberToPartition) {
String pivot = data.get(firstIndex);
int left = data.indexOf(firstIndex);
int right = data.indexOf(numberToPartition);
while (left <= right) {
while (data.get(left).compareTo(pivot) < 0) // this is where I get the error
left++;
while (data.get(right).compareTo(pivot) > 0)
right--;
if (left <= right) {
temp = data.get(left);
Collections.swap(data, left, right);
data.set(right, temp);
left++;
right--;
}
}
return left;
}
I have tried to debug my code but it seems that I just don't see a way to fix the error. Any help would be appreciated.
Why in the world are you doing
int left = data.indexOf(firstIndex);
int right = data.indexOf(numberToPartition);
? That looks for the the values of firstIndex and numberToPartition among the elements of the List being sorted. Those values are by no means certain to be present in the data, and even if they are, it is entirely coincidental. Their indices in the data are not meaningful.
In the event that one or both of those values is not present in the data, indexOf() returns -1, which you then happily pass to List.get().
It looks like what you want is more like
int left = firstIndex;
int right = firstIndex + numberToPartition - 1;
Make sure firstIndex does really occur in data, if not the .indexOf method returns -1 and you will get an java.lang.ArrayIndexOutOfBoundsException: -1 at int left = data.indexOf(firstIndex);

Java Quick Sort Implementation (Code fix)

I have written my version of the Quick Sort in Java but I'm running into a bit of a problem while calling the second recursion. This is my code:
public static int[] quickSort(int[] array, int start, int end) {
int pIndex;
if (start < end) {
int left = start;
int right = end - 1;
int pivot = array[end];
//Start the partitioning
while (left < right) {
if (array[left] > pivot && array[right] < pivot) {
int temp = array[left];
array[left] = array[right];
array[right] = temp;
left++;
right--;
} else if (array[left] > pivot)
right--;
else
left++;
}
if (array[end] < array[left]) {
int temp = array[left];
array[left] = array[end];
array[end] = temp;
pIndex = left;
} else
pIndex = end;
//End partitioning
quickSort(array, 0, pIndex - 1);
quickSort(array, pIndex + 1, array.length - 1);
}
return array;
}
The parameter start will be the index of the first element in the array and end will be the index of the last one and I am picking the last element as the pivot.
The issue I am running into is at quickSort(array, pIndex + 1, array.length - 1);
The array.length-1 causes this to go on infinitely since it is with reference to the original array. Is there any way for me to fix this without having to pass a new array to the function everytime?
I did try to create a global variable to store the new lengths but I wasn't able to do it quite right.
Thanks in advance.
I'm sorry if the code is not a very nice implementation of the Sort. I wanted to write one from scratch on my own but turns out I ran into problems anyway.
The proper way of using recursion in QuickSort is to use start, pivot and end.
You appear to be using inclusive-end indexing; then you will want to recurse into
quicksort(data, start, pivot - 1)
quicksort(data, pivot + 1, end)
The pivot element is already in its final position.

finding kth largest element in an array implemented bag

We have a collection of Comparables held in a bag and have to find the kth largest element. I copied the collection to a HashSet to remove duplicates, then converted the HashSet to an array to be sorted and consequently the kth element accessed. The code compiles, but fails the testing, and I can't figure out what's wrong. Any ideas?
public E kth(int k) {
uniqueSet();
Object[] uniqueArr = hashSet.toArray();
startQuick(uniqueArr);
return (E) uniqueArr[k - 1];
}
private void startQuick(Object[] uniqueArr) {
int i = 0, j = uniqueArr.length;
quickSort(uniqueArr, 0, j);
}
private void quickSort(Object[] uniqueArr, int i, int j) {
int index = partition(uniqueArr, i, j);
if (i < index - 1) {
quickSort(rankBagArr, index - 1, j);
}
if (index < j) {
quickSort(rankBagArr, i, index - 1);
}
}
private int partition(Object[] uniqueArr, int i, int j) {
E tmp;
E pivot = (E) rankBagArr[(i + j) / 2];
while (i <= j) {
while (rankBagArr[i].compareTo(pivot) < 0) {
i++;
}
while (rankBagArr[j].compareTo(pivot) > 0) {
j--;
}
if (i <= j) {
tmp = (E) rankBagArr[i];
rankBagArr[i] = rankBagArr[j];
rankBagArr[j] = tmp;
i++;
j--;
}
}
return i;
}
For a start this part is highly suspect:
if (i < index - 1)
quickSort(rankBagArr, index-1 ,j);
if (index < j)
quickSort(rankBagArr, i, index-1);
Don't you mean:
if (i < index - 1)
quickSort(rankBagArr, i, index-1);
if (index + 1 < j)
quickSort(rankBagArr, index + 1, j);
?
I'm not familiar with your approach to partitioning, so I don't know whether that's correct or not. I think I understand it, and it looks okay on inspection, but it's very easy to get off-by-one errors which are hard to see without careful study.
Here's a partition method I wrote in C# recently - you should be able to translate it into Java quite easily if you want to.
private static int Partition<T>(T[] array, int left, int right,
IComparer<T> comparer) {
// Pivot on the rightmost element to avoid an extra swap
T pivotValue = array[right];
int storeIndex = left;
for (int i = left; i < right; i++) {
if (comparer.Compare(array[i], pivotValue) < 0) {
Swap(array, i, storeIndex);
storeIndex++;
}
}
Swap(array, right, storeIndex);
return storeIndex;
}
static void Swap<T>(T[] array, int x, int y) {
T tmp = array[x];
array[x] = array[y];
array[y] = tmp;
}
Any reason for not just using Arrays.sort though?
If you want to solve the problem by sorting, then
Use sorting methods from API (Arrays.sort or Collections.sort). Reinventing the wheel is pointless.
Sort contents of your collection once, not every time you look for k-th element.
The quicksort partitioning is good for finding k-th element without sorting entire collection - you partition, if lowest range is larger then k, you recurrently go with partition to lower range, if it's smaller then k, you go to higher range and look for (k - size of lower range)-th element. It has better complexity than sorting whole collection. You can read more about it here
Anyway, your methods have parameter named uniqueArr, but some operations you perform on rankBagArr. Is it a typo? There is no definition of rankBagArr in your code.
May you could have a bit less of manipulations (and improve performance), and correct the default you are seeing...
Starting with a List (ArrayList), you could ask to sort it (using the comparator, and Collections.sort(list)). Then you could loop down and:
memorizing the last element
if you find the new element is not equals, increment a counter
when your counter reaches the k value, the current element is your target

Categories