Как найти самую длинную цепочку в массиве

Студворк — интернет-сервис помощи студентам

Доброго времени суток форумчане!
Препод взвалил непосильную на данный момент для меня задачку, с которой у меня возникли проблемы из за не знания алгоритма ее решения. Суть задачки проста: есть линейный массив, в котором в различном порядке идут цифры, необходимо вычислить цепочки повторяющихся элементов, точнее те которые по количеству самые большие, например:
входные данные 1,5,2,2,3,3,3,1,15,9,9,9,9
вывод: в данном ряде чаще всего повторяется число 9, в количестве 4 штук.
думал через switch но написав такую псевдо программу понял что не попрет: препод может ввести 15,15,15,15,
а это уже число а не цифра… уже не попрет… подскажите чем здесь можно воспользоваться?

Code

Using itertools.groupby (similar to @Moses Koledoye’s answer):

groups = [[y[1] for y in g] for k, g in itertools.groupby(enumerate(iterable), key=lambda x: x[0]-x[1])]
groups
# [[0, 1], [3], [5], [7, 8, 9, 10], [12, 13]]

max(groups, key=len)
# [7, 8, 9, 10]

Alternative

Consider the third-party tool more_itertools.consecutive_groups:

import more_itertools as mit


iterable = [0, 1, 3, 5, 7, 8, 9, 10, 12, 13]
max((list(g) for g in mit.consecutive_groups(iterable)), key=len)
# [7, 8, 9, 10]

вариант 1 (решение в лоб):

text = "XABXCABBBCAADBXXBAADX"

max_size = 0
size = 0
for letter in text:
    if letter in 'ABC':
        size += 1
    else:
        if max_size < size:
            max_size = size

        size = 0

if max_size < size:
    max_size = size

print(max_size)

вариант 2 (укороченный):

size, max_size = 0, 0

for letter in text:
    size, max_size = (size + 1, max_size) if letter in 'ABC' else (0, size if max_size < size else max_size)

max_size = size if max_size < size else max_size

вариант 3 (однострочный):

правда тут небольшой изврат и работает помедленнее предыдущего:

res = max(map(len, ''.join(letter if letter in 'ABC' else ' ' for letter in text)).split())

вариант 3.1 (чуть-чуть покороче):

res = max(map(len, ''.join((' ', letter)[letter in 'ABC'] for letter in text).split()))

var
a:array [1..10000] of integer;
b:array [1..10000] of integer;
c:array [1..10000] of integer;
i,j,k,m,n,z,max:integer;
begin
k:=0;
m:=0;
writeln (‘Введите число n’);
readln (n);
writeln (‘Заполните массив’);
for i:=1 to n do begin
write (‘a[‘,i,’]=’); readln (a[i]);
end;
j:=1;
z:=1;
for i:=1 to n-1 do begin
if (a[i]=a[i+1]) then
k:=k+1
else begin
c[z]:=a[i];
b[j]:=k+1;
k:=0;
j:=j+1;
z:=z+1;
m:=m+1;
end;
b[j]:=k+1;
c[z]:=a[i];
end;
max:=b[1];
z:=1;
for j:=2 to m+1 do
if (b[j]>max) then begin
max:=b[j];
z:=j;
end;
writeln (‘Самая длинная цепочка из ‘,c[z]);
writeln (‘Встречается ‘,max,’ раз’);
end.

С++: самая длинная цепочка элементов, для которой выполняется признак, или «указатель на шаблон функции»

Представим, что мы хотим реализовать на C++ некий алгоритм, например, поиск в массиве самой длинной цепочки элементов, отвечающих какому-либо признаку (отрицательность значения, чётность целочисленного значения, первый символ строки является латинской гласной и т.п.).

При этом нам хочется, чтобы алгоритм работал с разнотипными данными, например, и с числами, и со строками.
Сам по себе код, реализованный в функции max_series, несложен — мы ищем очередной элемент, отвечающий нужному признаку f и считаем длину цепочки таких элементов, запоминая номер первого элемента цепочки в переменной start, а длину цепочки — в переменной maxlen.

Существенней то, что проверять на соответствие признаку нужно разнотипные элементы, а значит, алгоритму следует передать указатель на функцию, получающую входной параметр нужного типа данных — того же, что у элементов массива.
Помочь может механизм шаблонов, с той оговоркой, что создать «указатель на шаблон функции» и использовать его, например, в качестве параметра другой функции, в C++ невозможно.

Шаблон функции — это не функция, а инструкция компилятору сгенерировать набор функций, отличающихся между собой типами параметров.

Соответственно, тип «указателя на шаблон функции» невозможен. Шаблон просто не имеет адреса памяти, на который мог бы сослаться указатель.

«Указатель на шаблон» можно объявить только после подстановки конкретного типа вместо class Type, тогда у функции появится и адрес в памяти.

Иными словами, template существует только в исходном коде. В исполняемый код попадает экземпляр (instance) шаблона, специализированного конкретными типами.

Соответственно, использовать оператор typedef для объявления такого указателя тоже нельзя.

К счастью, если написать обычную функцию-шаблон, аргументом которой инстанцируется ещё одна шаблонная функция для проверки элемента типа T на нужное свойство, то адрес такой функции вполне можно передать и решить нашу задачу, по коду, наверное, сказанное будет понятней:

#include <iostream>
#include <cstring>
using namespace std;

template <typename T>
void max_series (int n, T *a, int (*f)(T), int &start, int &maxlen) {
 int i=0,len,s;
 start=-1; maxlen=0;
 while (i<n) {
  while (f(a[i])==0) {
   i++;
   if (i==n) return;
  }
  len = 0; s = i;
  while (f(a[i])==1) {
   len++;
   if (len>maxlen) { maxlen=len; start=s; }
   i++;
   if (i==n) return;
  }
 }
}

template <typename T> int f1 (T a) { return a<0; }
template <typename T> int f2 (T a) { return ((int)a)%2==0; }
template <typename T> int f3 (T a) { return strchr("eyuioaEYUIOA",a[0])?1:0; }

int main () {
 const int n=8;
 int a[n]={1,2,-3,-4,-8,-6,8,-8}; //Массив с данными-числами
 int start,len; //начало и длина самой длинной цепочки

 //Применям алгоритм для поиска разных цепочек:
 max_series (n,a,&f1<int>,start,len); //...отрицательных элементов
 cout << endl << start << "," << len;
 max_series (n,a,&f2<int>,start,len); //...и делящихся на 2 без остатка
 cout << endl << start << "," << len;

 char *b[n]={"abba","bobina","yana","ilky","yeah","ugogo","sava","head"}; //Массив строк
 max_series (n,b,&f3<char *>,start,len); //...или вообще строк, начинающихся с гласных
 cout << endl << start << "," << len;

 cin.get();
 return 0;
}

Как видим, один и тот же код может проверять не только разные признаки для элементов массива, но и работать с массивами разных типов данных.

Проверено в консолях Studio 2015 и QT5, работает. Ну и полезно для размышлений на тему функций-делегатов в современных IDE :)

Что касается указателей на функции, помните главное — им можно присваивать адреса разных функций, но построенных по одному прототипу.

Мы можем определить нужный набор функций, одинаковых по списку параметров, создать указатель на функцию (typedef в C++ не нужен) и затем программно ставить указатель на нужную функцию, косвенно вызывая её:

#include <iostream>
using namespace std;

int f1 (int x) { return x+1; }
int f2 (int x) { return x+2; }

int main() {
 int x = 0;
 int(*pf)(int); //определяем указатель на функцию
 
 pf = &f1;
 cout << pf(x); //1
 pf = &f2;
 cout << endl << pf(x); //2
 cin.get();	return 0;
}

Другой вариант — определить тип указателя на нужный тип функций, потом создать массив объектов этого типа, инициализировать его адресами функций и в нужный момент вызывать нужную функцию:

#include <iostream>
using namespace std;

typedef int(*fptr)(int);  //определяем тип указателя на нужный тип функций

int f1 (int x) { return x+1; }
int f2 (int x) { return x+2; }

int main() {
 int x = 0;
 fptr pf[2] = { &f1, &f2 };
 
 cout << pf[0](x); //1
 cout << endl << pf[1](x); //2
 cin.get();	return 0;
}

Следует понимать, что задавая шаблон функции, мы определяем обобщённый (абстрактный) алгоритм, который должен быть применим к объектам разных типов данных T:

#include <iostream>
#include <string>
using namespace std;

template <class T>
T max(T a, T b) {
 return (a>b ? a : b);
}

int main() {
 int a = 3, b = 5;
 cout << max(a, b); //5
 string c = "vvv", d = "www";
 cout << endl << max(c, d); //www

 cin.get(); return 0;
}

В общем случае можно обьявить шаблонный класс, затем создать экземпляры класса с нужным типом и создать на них указатели.
Уже через эти указатели мы можем обрашаться к методам экземпляров, параметры и возвращаемые значения которых будут нужного типа.

Наконец, если мы стремимся создать шаблон, который бы генерировал функцию, вызывающую другую функцию, которую мы передали первой в шаблоне, и не хотим передавать указатель в качестве аргумента, помочь может показанный ниже подход со структурой-«обёрткой» executor.

#include <iostream>
using namespace std;

template < int(*func_ptr)(int, int) >
struct executor {
 int operator() (int a, int b) { return func_ptr(a, b); }
};

int fplus (int a, int b) { return a + b; }
int fminus (int a, int b) { return a - b; }

int main() {
	executor <&fplus> algorythm1;
	cout << algorythm1(1, 2); //3
	executor <&fminus> algorythm2;
	cout << endl << algorythm2(1, 2); //-1
	cin.get(); return 0;
}

29.05.2017, 22:06 [3404 просмотра]


К этой статье пока нет комментариев, Ваш будет первым

Понравилась статья? Поделить с друзьями:
  • Как найти острый угол ромба по диагоналям
  • Как найти площадь усеченной пирамиды правильной четырехугольной
  • Как исправить дворники на гранте
  • Как найти квадрат длины бокового ребра пирамиды
  • Как найти владельца airpods по серийному номеру