Dafny: verify test case of array sorting with duplicates - sorting

Given the usual specification of array sorting in Dafny,
method sort(a: array<T>)
modifies a
ensures isSorted(a[..])
ensures multiset(a[..]) == multiset(old(a[..]))
predicate isSorted(s: seq<T>) {
forall i, j :: 0 <= i < j < |s| ==> s[i] <= s[j]
}
Dafny is able to check a "test case" without duplicates (with a small help)
method testSortWithoutDups() {
var a := new T[] [9, 4, 6, 3, 8];
assert a[..] == [9, 4, 6, 3, 8]; // small prover helper!
sort(a);
assert a[..] == [3, 4, 6, 8, 9];
}
But is not able to check a "test case" with duplicates, so I tried using a lemma as follows:
method testSortWithDups() {
var a := new T[] [9, 3, 6, 9];
assert a[..] == [9, 3, 6, 9]; // small prover helper!
sort(a);
SortingProp(a[..], [3, 6, 9, 9]);
assert a[..] == [3, 6, 9, 9];
}
// State and prove by induction the property that, if two sequences are sorted and have
// the same elements, then they must be identical (so sorting has a unique solution).
// Most of the proof steps are filled in by Dafny.
lemma SortingProp(a: seq<T>, b: seq<T>)
requires isSorted(a) && isSorted(b) && multiset(a) == multiset(b)
ensures a == b
{
seqProps(a);
seqProps(b);
if |a| > 0 {
SortingProp(a[1..], b[1..]);
}
}
// Two usefull properties about sequences and their multisets (proved by Dafny alone):
lemma seqProps(a: seq<T>)
ensures |a| > 0 ==> a == [a[0]] + a[1..]
ensures forall i :: 0 <= i < |a| ==> a[i] in multiset(a)
{}
Is there a better solution?

Yeah, it's too much to hope for that the verifier would prove this entirely automatically. Your decomposition into lemmas and the particular properties you're stating are perfect! Well done!

Related

Length of maximum continuous subarray with 2 unique numbers

I have an array of numbers and I want to figure out the maximum length of a continuous subarray of 2 unique numbers repeating.
For example, [2, 3, 4, 3, 2, 2, 4] would return 3 since [3, 2, 2] is of length 3.
[2, 4, 2, 5, 1, 5, 4, 2] would return 3.
[7, 8, 7, 8, 7] would return 5.
Edit: I have considered an O(n^2) solution where I start at each value in the array and iterate until I see a third unique value.
for item in array:
iterate until third unique element
if length of this iteration is greater than existing max, update the max length
return maxlength
I do not, however, think this is an efficient solution.
It can be done O(n). The code is in python3. o and t are one and two respectively. m is the max and c is the current count variable.
a = [7, 8, 7, 8, 7]
m = -1
o = a[0]
t = a[1]
# in the beginning one and two are the first 2 numbers
c = 0
index = 0
for i in a:
if i == o or i == t:
# if current element is either one or two current count is increased
c += 1
else:
# if current element is neither one nor two then they are updated accordingly and max is updated
o = a[index - 1]
t = a[index]
m = max(m, c)
c = 2
index += 1
m = max(m, c)
print(m)
We can use two pointer technique to solve this problem in O(n) run time complexity. These two pointer for example startPtr and endPtr will represent the range in the array. We will maintain this range [startPtr, endPtr] in such way that it contains no more than 2 unique number. We can do this by keeping track of position of the 2 unique number. My implement in C++ is given below:
int main()
{
int array[] = {1,2,3,3,2,3,2,3,2,2,2,1,3,4};
int startPtr = 0;
int endPtr = 0;
// denotes the size of the array
int size= sizeof(array)/sizeof(array[0]);
// contain last position of unique number 1 in the range [startPtr, endPtr]
int uniqueNumPos1 = -1; // -1 value represents it is not set yet
// contain last position of unique number 2 in the range [startPtr, endPtr]
int uniqueNumPos2 = -1; // -1 value represents it is not set yet
// contains length of maximum continuous subarray with 2 unique numbers
int ans = 0;
while(endPtr < size) {
if(uniqueNumPos1 == -1 || array[endPtr] == array[uniqueNumPos1]) {
uniqueNumPos1 = endPtr;
}
else {
if(uniqueNumPos2 == -1 || array[endPtr] == array[uniqueNumPos2]) {
uniqueNumPos2 = endPtr;
}
else {
// for this new third unique number update startPtr with min(uniqueNumPos1, uniqueNumPos2) + 1
// to ensure [startPtr, endPtr] does not contain more that two unique
startPtr = min(uniqueNumPos1, uniqueNumPos2) + 1;
// update uniqueNumPos1 and uniqueNumPos2
uniqueNumPos1 = endPtr -1;
uniqueNumPos2 = endPtr;
}
}
// this conditon is to ensure the range contain exactly two unique number
// if you are looking for the range containing less than or equal to two unique number, then you can omit this condition
if (uniqueNumPos1 != -1 && uniqueNumPos2 !=-1) {
ans = max( ans, endPtr - startPtr + 1);
}
endPtr++;
}
printf("%d\n", ans);
}
Thanks #MBo for pointing out the mistakes.
import java.util.Arrays;
import static java.lang.System.out;
class TestCase{
int[] test;
int answer;
TestCase(int[] test,int answer){
this.test = test;
this.answer = answer;
}
}
public class Solution {
public static void main(String[] args) {
TestCase[] tests = {
new TestCase(new int[]{2, 3, 4, 3, 2, 2, 4},3),
new TestCase(new int[]{2, 3, 3, 3, 3, 4, 3, 3, 2, 2, 4},7),
new TestCase(new int[]{1,2,3,3,4,2,3,2,3,2,2,2,1,3,4},7),
new TestCase(new int[]{2, 7, 8, 7, 8, 7},5),
new TestCase(new int[]{-1,2,2,2,2,2,2,2,2,2,2,-1,-1,4},13),
new TestCase(new int[]{1,2,3,4,5,6,7,7},3),
new TestCase(new int[]{0,0,0,0,0},0),
new TestCase(new int[]{0,0,0,2,2,2,1,1,1,1},7),
new TestCase(new int[]{},0)
};
for(int i=0;i<tests.length;++i){
int ans = maxContiguousArrayWith2UniqueElements(tests[i].test);
out.println(Arrays.toString(tests[i].test));
out.println("Expected: " + tests[i].answer);
out.println("Returned: " + ans);
out.println("Result: " + (tests[i].answer == ans ? "ok" : "not ok"));
out.println();
}
}
private static int maxContiguousArrayWith2UniqueElements(int[] A){
if(A == null || A.length <= 1) return 0;
int max_subarray = 0;
int first_number = A[0],second_number = A[0];
int start_index = 0,same_element_run_length = 1;
for(int i=1;i<A.length;++i){
if(A[i] != A[i-1]){
if(first_number == second_number){
second_number = A[i];
}else{
if(A[i] != first_number && A[i] != second_number){
max_subarray = Math.max(max_subarray,i - start_index);
start_index = i - same_element_run_length;
first_number = A[i-1];
second_number = A[i];
}
}
same_element_run_length = 1;
}else{
same_element_run_length++;
}
}
return first_number == second_number ? max_subarray : Math.max(max_subarray,A.length - start_index);
}
}
OUTPUT:
[2, 3, 4, 3, 2, 2, 4]
Expected: 3
Returned: 3
Result: ok
[2, 3, 3, 3, 3, 4, 3, 3, 2, 2, 4]
Expected: 7
Returned: 7
Result: ok
[1, 2, 3, 3, 4, 2, 3, 2, 3, 2, 2, 2, 1, 3, 4]
Expected: 7
Returned: 7
Result: ok
[2, 7, 8, 7, 8, 7]
Expected: 5
Returned: 5
Result: ok
[-1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, 4]
Expected: 13
Returned: 13
Result: ok
[1, 2, 3, 4, 5, 6, 7, 7]
Expected: 3
Returned: 3
Result: ok
[0, 0, 0, 0, 0]
Expected: 0
Returned: 0
Result: ok
[0, 0, 0, 2, 2, 2, 1, 1, 1, 1]
Expected: 7
Returned: 7
Result: ok
[]
Expected: 0
Returned: 0
Result: ok
Algorithm:
So, we maintain 2 variables first_number and second_number which will hold those 2 unique numbers.
As you know, there could be many possible subarrays we have to consider to get the max subarray length which has 2 unique elements. Hence, we need a pointer variable which will point to start of a subarray. In this, that pointer is start_index.
Any subarray breaks when we find a third number which is not equal to first_number or second_number. So, now, we calculate the previous subarray length(which had those 2 unique elements) by doing i - start_index.
Tricky part of this question is how to get the start_index of the next subarray.
If you closely observe, second_number of previous subarray becomes first_number of current subarray and third number we encountered just now becomes second_number of this current subarray.
So, one way to calculate when this first_number started is to run a while loop backwards to get that start_index. But that would make the algorithm O(n^2) if there are many subarrays to consider(which it will be).
Hence, we maintain a variable called same_element_run_length which just keeps track of the length or frequency of how many times the number got repeated and gets updated whenever it breaks. So, start_index for the next subarray after we encounter the third number becomes start_index = i - same_element_run_length.
Rest of the computation done is self-explanatory.
Time Complexity: O(n), Space Complexity : O(1).

An efficient method to generate all possible ways to pair up items in a data set

This is somewhat of a combinatorial problem; I'm trying to figure out an efficient way to pair up all items in a data set.
For example, I have an array of length 6: [1,2,3,4,5,6], and I want to make all possible pairings of the contents in the array as so:
[1,2],[3,4],[5,6]
[1,2],[3,5],[4,6]
[1,2],[3,6],[4,5]
[1,3],[2,4],[5,6]
[1,3],[2,5],[4,6]
...
and so on. In this example, there would be 15 combinations total. In general, the number of possibilities in this solution should be (N-1)!! where N is the length of the array or the number of items to be paired up. N will always be even in this case. Ideally, an algorithm will generate all possibilities serially, without having to store very large arrays.
For example, one way would work somewhat like a 'round robin' scheduling algorithm where you split the array into N/2:
[1,2,3]
[4,5,6]
and rotate the [5,3,6] clockwise to generate 3 unique pairings (counting vertically) with [1,2,4] fixed as so:
[1,2,3]
[4,5,6]
[1,2,5]
[4,6,3]
[1,2,6]
[4,3,5]
and then rotate [4,2,3,6,5] clockwise to generate 5 unique pairings with [1] fixed, going from the smallest innermost case (N=4) outwards until the end, but recursively. As it is I'm not sure how to best express this as code or if there is a more efficient way of doing this, as N can be very large.
You can generate the pairs using the standard recursive algorithm for generating permutations of a list, but with a twist that each time you recurse you advance 2 elements along the list, and the first remaining element in the list is always the first element of the pair you output at each recursion, with the second of the pair being each of the other remaining elements.
Always choosing the first remaining element as the first item in the pair avoids generating the same pairings with the pairs in different order.
As with the standard algorithm, you can generate the permutations in place without making copies of the array, by swapping elements in place, recursing and then swapping back.
Here is some C code to demonstrate the algorithm (I realise this question is tagged Fortran but just think of it as pseudo code). This code passes the list and count when it recurses, but you could implement it with items and itemcount as global variables:
// start is the current position in the list, advancing by 2 each time
// pass 0 as start when calling at the top level
void generatePairings(int* items, int itemcount, int start)
{
if(itemcount & 1)
return; // must be an even number of items
// is this a complete pairing?
if(start == itemcount)
{
// output pairings:
int i;
for(i = 0; i<itemcount; i+=2)
{
printf("[%d, %d] ", items[i], items[i+1]);
}
printf("\n");
return;
}
// for the next pair, choose the first element in the list for the
// first item in the pair (meaning we don't have to do anything
// but leave it in place), and each of the remaining elements for
// the second item:
int j;
for(j = start+1; j<itemcount; j++)
{
// swap start+1 and j:
int temp = items[start+1];
items[start+1] = items[j];
items[j] = temp;
// recurse:
generatePairings(items, itemcount, start+2);
// swap them back:
temp = items[start+1];
items[start+1] = items[j];
items[j] = temp;
}
}
int main(void) {
int items[6] = {1, 2, 3, 4, 5, 6};
generatePairings(items, 6, 0);
return 0;
}
Output:
[1, 2] [3, 4] [5, 6]
[1, 2] [3, 5] [4, 6]
[1, 2] [3, 6] [5, 4]
[1, 3] [2, 4] [5, 6]
[1, 3] [2, 5] [4, 6]
[1, 3] [2, 6] [5, 4]
[1, 4] [3, 2] [5, 6]
[1, 4] [3, 5] [2, 6]
[1, 4] [3, 6] [5, 2]
[1, 5] [3, 4] [2, 6]
[1, 5] [3, 2] [4, 6]
[1, 5] [3, 6] [2, 4]
[1, 6] [3, 4] [5, 2]
[1, 6] [3, 5] [4, 2]
[1, 6] [3, 2] [5, 4]
If you are doing this on a list of large objects, it's more efficient to permute a list of indices and then use those to index into your array of objects, rather than doing expensive swap operations on large amounts of data.
Wow. Now there's a blast from the past. I wrote about this back in 1993 and provided Pascal source code for it. Surprisingly, the article in which it appeared is available online at http://www.drdobbs.com/database/algorithm-alley/184409099#02e5_000d.
Basically, I adapted a selection sort algorithm:
for x = 0 to n-2
for y = x+1 to n-1
write x, y
The problem with that approach is that it generates {1,2},{1,3},{1,4},{2,3},{2,4}...
It turns out that you can modify that output by maintaining a swap array that you manipulate after every iteration of the outer loop. Here's the Pascal source code that I supplied with the article.
(* ----------------------------------------------------------- *(
** pairings.pas -- Select sports-event team pairings **
** ------------------------------------------------------------**
** This program generates team pairings for sports events. **
** Each team is guaranteed to play each other team exactly **
** once. No team will play more than one game per day. **
** An asterisk ('*') means a day off for that team. **
** For example, 5 teams produces this output: **
** Day 1 - 12 34 5* **
** Day 2 - 13 25 4* **
** Day 3 - 14 2* 35 **
** Day 4 - 15 3* 24 **
** Day 5 - 1* 45 23 **
** ------------------------------------------------------------**
** Copyright (c) 1993 by Jim Mischel. All rights reserved. **
)* ----------------------------------------------------------- *)
program pairings;
const
TEAMCOUNT = 5;
var
TeamNames: Array [1 .. TEAMCOUNT + 1] of Char;
SwapArray: Array [1 .. TEAMCOUNT + 1] of Integer;
x, Temp, Day: Integer;
TempChar: Char;
const
NTeams: Integer = TEAMCOUNT;
begin
{ Set up team names. Normally read from a file. }
for x := 1 to NTeams do
TeamNames[x] := Chr(x + Ord('0'));
if Odd(NTeams) then
begin
NTeams := NTeams + 1;
TeamNames[NTeams] := '*'
end;
{ Set up the array that controls swapping. }
for x := 1 to NTeams do
SwapArray[x] := x;
for Day := 1 to NTeams - 1 do
begin
Write('Day ', Day, ' -');
{ Write the team pairings for this day }
x := 1;
while x < NTeams do
begin
Write(' ', TeamNames[x], TeamNames[x + 1]);
x := x + 2;
end;
WriteLn;
{ Perform swaps to prepare array for next day's pairings. }
if Odd(Day)
then x := 2
else x := 3;
while x < NTeams do
begin
TempChar := TeamNames[SwapArray[x]];
TeamNames[SwapArray[x]] := TeamNames[SwapArray[x + 1]];
TeamNames[SwapArray[x + 1]] := TempChar;
Temp := SwapArray[x];
SwapArray[x] := SwapArray[x + 1];
SwapArray[x + 1] := Temp;
x := x + 2
end
end
end.
For those looking for less of a mathematical solution but utilizing data structure in JS. A combination of maps, set, and recursion:
function findUnmatchedCouples(people, couples) {
const copy = [...people]
if (copy.length == 0) {
return;
}
const p = copy[0];
copy.splice(0, 1);
for (let i = 0; i < copy.length; i++) {
const q = copy[i];
if (matchedThisRound.has(p)) {
continue;
}
if (!isCouple(p, q)) {
copy.splice(i, 1);
findUnmatchedCouples(copy, couples);
couples.push([p, q]);
matchedThisRound.add(p);
registerCouple(p, q)
}
}
return couples;
}
function isCouple(p, q) {
if (!registered.has(p)) {
return false;
} else {
const currentset = registered.get(p)
if (currentset.has(q)) {
//console.log(`${p} already matched with ${q}`)
return true;
}
currentset.add(q)
registered.set(p, currentset)
}
return false;
}
function registerCouple(p, q) {
if (!registered.has(p)) {
registered.set(p, new Set([q]))
} else {
const currentset = registered.get(p)
currentset.add(q)
registered.set(p, currentset)
}
}
//Start Secret Santa
const people = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
for (let i = 0; i < 10; i++) {
matchedThisRound = new Set([]);
console.log(`round ${i}`)
console.log(findUnmatchedCouples(people, []))
}

How do you check if one array is a subsequence of another?

I'm looking to explore different algorithms, both recursive and dynamic programming, that checks if one arrayA is a subsequence of arrayB. For example,
arrayA = [1, 2, 3]
arrayB = [5, 6, 1, 7, 2, 9, 3]
thus, arrayA is indeed a subsequence of arrayB.
I've tried a few different searches, but all I can seem to find is algorithms to compute the longest increasing subsequence.
Since you must match all elements of arrayA to some elements of arrayB, you never need to backtrack. In other words, if there are two candidates in arrayB to match an element of arrayA, you can pick the earliest one, and never retract the choice.
Therefore, you do not need DP, because a straightforward linear greedy strategy will work:
bool isSubsequence(int[] arrayA, int[] arrayB) {
int startIndexB = 0;
foreach (int n in arrayA) {
int next = indexOf(arrayB, startIndexB , n);
if (next == NOT_FOUND) {
return false;
}
startIndexB = next+1;
}
return true;
}
As dasblinkenlight has correctly said(and i could not have phrased it better than his answer!!) a greedy approach works absolutely fine. You could use the following pseudocode (with just a little more explanation but totally similar to what dasblinkenlight has written)which is similar to the merging of two sorted arrays.
A = {..}
B = {..}
j = 0, k = 0
/*j and k are variables we use to traverse the arrays A and B respectively*/
for(j=0;j<A.size();){
/*We know that not all elements of A are present in B as we
have reached end of B and not all elements of A have been covered*/
if(k==B.size() && j<A.size()){
return false;
}
/*we increment the counters j and k both because we have found a match*/
else if(A[j]==B[k]){
j++,k++;
}
/*we increment k in the hope that next element may prove to be an element match*/
else if(A[j]!=B[k]){
k++;
}
}
return true; /*cause if we have reached this point of the code
we know that all elements of A are in B*/
Time Complexity is O(|A|+|B|) in the worst case, where |A| & |B| are the number of elements present in Arrays A and B respectively. Thus you get a linear complexity.
As #sergey mentioned earlier, there is no need to do backtracking in this case.
Here just another Python version to the problem: [Time complexity: O(n) - worst]
>>> A = [1, 2, 3]
>>> B = [5, 6, 1, 7, 8, 2, 4, 3]
>>> def is_subsequence(A, B):
it = iter(B)
return all(x in it for x in A)
>>> is_subsequence(A, B)
True
>>> is_subsequence([1, 3, 4], B)
False
>>>
Here is an example in Ruby:
def sub_seq?(a_, b_)
arr_a = [a_,b_].max_by(&:length);
arr_b = [a_,b_].min_by(&:length);
arr_a.select.with_index do |a, index|
arr_a.index(a) &&
arr_b.index(a) &&
arr_b.index(a) <= arr_a.index(a)
end == arr_b
end
arrayA = [1, 2, 3]
arrayB = [5, 6, 1, 7, 2, 9, 3]
puts sub_seq?(arrayA, arrayB).inspect #=> true
Here is an example in GOLANG...
func subsequence(first, second []int) bool {
k := 0
for i := 0; i < len(first); i++ {
j := k
for ; j < len(second); j++ {
if first[i] == second[j] {
k = j + 1
break
}
}
if j == len(second) {
return false
}
}
return true
}
func main(){
fmt.Println(subsequence([]int{1, 2, 3}, []int{5, 1, 3, 2, 4}))
}

How to find duplicate element in array and return duplicate index

I need to find duplicate latitude in an array and nudge it a bit to avoid marker display problem.
I searched and find a way to do it in ruby:
1.find duplicate element in ruby
(I consider sort array element and check adjacent element)
2.use array.indexof() to get its index(may have 3 or more duplicate element)
This works sure but I feel its not the best way. Is there a way to find duplicate and index of duplicate in one go?
Thanks in advance
EDIT:
I've find a way,check duplicate and change on spot.
But the problem is this function change all duplicate value to another duplicated value.
I think its because the main array is not updated during check and change procedure, attached is my code,anyway to improve it?
#ln=0
for #ln in 0..#checkLocation.length-1 do
if (!(#checkLocation.index(#existlat)==nil) && (#existlat!=nil))
#checkLocation[#ln]=#checkLocation[#ln]+0.00001
end
#existlat=#checkLocation[#ln]
end
a = [:a, :b, :c, :b, :d, :a, :e]
a.each_index.group_by{|i| a[i]}.values.select{|a| a.length > 1}.flatten
# => [0, 5, 1, 3]
Finding dupes is not very difficult if performance is not a real issue for you.
The most natural way would be to compare each element with all the other elements:
for (int i = 0; i < arraySize-1; ++i) {
for (int j = i+1; j < arraySize; ++j) {
if(array[i] == array[j]) changeDupe(array[j]);
}
}
The code above will allow you to change all the dupes.
Example in execution, changin dupes to 0:
Input: {1, 2, 3, 2, 1, 4, 5, 6, 8, 2}
Output: {1, 2, 3, 0, 0, 4, 5, 6, 8, 0}
Another way to achieve this is to use a second array. If you are using integer values, you can make it like this:
int input[10] = {1, 2, 3, 2, 1, 4, 5, 6, 8, 2};
bool output[10] = {false, false, false, false, false, false, false, false, false, false};
for (int i = 0; i < arraySize; ++i) {
if (output[input[i]] == false) changeDupe(input[i]));
else output[input[i]] = true;
}
However, if one of your elements is bigger than the size of your array you will have a boundary problem. Suppose you have the value 100, then you would be trying to access the 100th element of the boolean array.
If you want to use the second algorithm but you are not working with an integer array, you could use a map to map each value on your array to an int, and then use the map value to set the booleans.
A pseudocode would look like this:
Map<yourData, int> map;
map<someValue, 1>;
map[someValue] = 1; //work based on this return value;
Yeeeet another way is to sort the array before iterating over it, and stop once you hit a different number. This would diminish the number of times you iterate over the array, but you would be adding the sorting algorithm complexity (probably O(n log(n))).
The code would look something like this:
int i = 0;
while (i < arraySize-1) {
if(array[i] == array[i+1])
array[i] = 0;
i++;
}
Input: {1, 1, 2, 3, 3, 4, 5, 6, 7, 8};
Output: {0, 1, 2, 0, 3, 4, 5, 6, 7, 8}
Complexity:
for the first algorithm, you would have N*(N-1) which I would say is O(n²).
for the second is O(n), but restrictions apply.
for the third, it would be the sort + O(n) for the loop.

Given integers how do I find asc and desc sequences of three?

I have integers i.e. 9, 5, 4, 3, 1, 6, 7, 8. I want to return the index where a sequence of three descending or ascending integers exists. In the example above I would get indices 1 and 5. What is the ruby code for this?
def seq
array = [9,5,4,3,1,6,7,8]
array.each_with_index |val, index|
if (val < (array[index + 1]).val < (array[index + 1]).val)
puts "#{index}"
# Skip two indexes
end
end
I think the logic behind your solution is almost correct, but your syntax is pretty far off from valid Ruby.
Here are a pair of pretty verbose solutions that will (hopefully) be fairly obvious:
numbers = [9, 6, 5, 4, 3, 1, 6, 7, 8]
# Find non-overlapping sets
i = 0
until i > numbers.length - 2
a, b, c = numbers[i..i + 2]
if (a - b == b - c) && (a - b).abs == 1
puts "#{i} (#{a},#{b},#{c})"
# Skip next two indexes
i += 3
else
i += 1
end
end
# Find overlapping sets (same solution, but don't skip indexes)
(0...numbers.length - 2).each do |i|
a, b, c = numbers[i..i + 2]
if (a - b == b - c) && (a - b).abs == 1
puts "#{i} (#{a},#{b},#{c})"
end
end
Since the question is not clear enough. I will assume the question is about finding 3 ascending or descending continuous numbers. If the length of the satisfied sequence it longer than 3, e.g [2, 3, 4, 5], it returns 0 and 1.
Here is the algorithm, do list[index] - list[index - 1] for all elements, and repeat it for another time, the answer will be the index of 0 elements after the calculation.
Intuitively,
original 9, 5, 4, 3, 1, 6, 7, 8
first pass -4, -1, -1, -2, 5, 1, 1
2nd pass 3, 0, -1, 7, 4, 0 -> the answer will be the indexes of 0's, which is 1, 5
Algorithm:
lst = [9, 5, 4, 3, 1, 6, 7, 8]
lst1 = lst.each_cons(2).map{ |a, b| b-a }
lst2 = lst1.each_cons(2).map{ |a, b| b-a }
result = lst2.each_index.select{|i| lst2[i] == 0}
result = [1, 5]
Here’s a solution using each_cons(3).with_index:
[9,5,4,3,1,6,7,8].each_cons(3).with_index.select { |s, i| s[0] < s[1] && s[1] < s[2] }.map(&:last)

Resources