Search
Write a publication
Pull to refresh
1
0
Сергей @z_serg

User

Send message

По crossing_lans, в этом случае порождается куча массив без пересечений и увеличивается время выполнения.

В части 2 предложу такой вариант, у меня выполнился за 0.4 сек.

WITH src AS 
(
SELECT 
	line[1] nodefrom,
	line[2] nodeto
FROM 
	regexp_matches(
$$
kh-tc
qp-kh
de-cg
ka-co
yn-aq
qp-ub
cg-tb
vc-aq
tb-ka
wh-tc
yn-cg
kh-ub
ta-co
de-co
tc-td
tb-wq
wh-td
ta-ka
td-qp
aq-cg
wq-ub
ub-vc
de-ta
wq-aq
wq-vc
wh-yn
ka-de
kh-ta
co-tc
wh-qp
tb-vc
td-yn
$$
,
'(\w+)\-(\w+)'
,'g'
) AS src(line)
)
,transform_src AS (
SELECT 
	nodefrom,nodeto 
FROM 
	src 
UNION ALL 
SELECT 
	nodeto,nodefrom 
FROM 
	src
)
,full_links AS 
(
--полный набор узлов включая узел источник
SELECT  
	nodefrom,
	nodefrom || array_agg(nodeto) AS links
FROM 
	transform_src
GROUP BY 
	nodefrom
)
,crossing_lans AS 
(
--найти пересечения узлов в массивах и сформировать из них новый массив
SELECT 
	array_agg(l1 ORDER BY l1) AS nodes
FROM 
	full_links AS fl1 
	CROSS JOIN full_links AS fl2,
	unnest(fl1.links) AS l1,
	unnest(fl2.links) AS l2
WHERE 
	fl1.nodefrom > fl2.nodefrom
	AND l1 = l2
GROUP BY 
	fl1.nodefrom || fl2.nodefrom
)
--TABLE crossing_lans;
SELECT 
	array_to_string(nodes,',')
FROM 
	crossing_lans 
GROUP BY 
	nodes
HAVING 
	--Кол-во комбинаций узлов fl1.nodefrom и fl2.nodefrom = арифметметической прогрессии от длины массива
	count(*) = array_length(nodes,1) * (array_length(nodes,1) - 1) / 2
ORDER BY 
	count(*) DESC 
LIMIT 1;

В части 1, получилось меньше 0.1сек вместо 3.5сек в части 1(снова)

WITH src AS 
(
SELECT 
	line[1] nodefrom,
	line[2] nodeto
FROM 
	regexp_matches(
$$
kh-tc
qp-kh
de-cg
ka-co
yn-aq
qp-ub
cg-tb
vc-aq
tb-ka
wh-tc
yn-cg
kh-ub
ta-co
de-co
tc-td
tb-wq
wh-td
ta-ka
td-qp
aq-cg
wq-ub
ub-vc
de-ta
wq-aq
wq-vc
wh-yn
ka-de
kh-ta
co-tc
wh-qp
tb-vc
td-yn
$$
,
'(\w+)\-(\w+)'
,'g'
) AS src(line)
),
transform_src AS (
SELECT 
	nodefrom,nodeto FROM src 
UNION ALL 
SELECT 
	nodeto,nodefrom FROM src
),
--каждый узел по списком связей
node_links AS 
(
SELECT  
	nodefrom,
	array_agg(nodeto) AS links
FROM 
	transform_src
GROUP BY 
	nodefrom
--исключить заведомо неподходящие
HAVING 
	nodefrom LIKE 't%' OR bool_or(nodeto ^@ 't') 
)
SELECT count(DISTINCT 
	(
	LEAST(nl1.nodefrom,nl2.nodefrom,u1),
	(array_remove(
		array_remove(ARRAY[nl1.nodefrom,nl2.nodefrom,u1],
					 LEAST(nl1.nodefrom,nl2.nodefrom,u1)),
		GREATEST(nl1.nodefrom,nl2.nodefrom,u1)))[1],
	GREATEST(nl1.nodefrom,nl2.nodefrom,u1)
	)
	)	
FROM 
	node_links AS nl1 
	CROSS JOIN node_links nl2,
	unnest(nl1.links) u1
WHERE 
	nl1.nodefrom > nl2.nodefrom
	AND nl2.nodefrom = ANY(nl1.links)
	AND u1 = ANY(nl2.links)
	AND (nl1.nodefrom ^@ 't' OR nl2.nodefrom ^@ 't' OR u1 ^@ 't');

WITH RECURSIVE r AS 
(
	WITH nums AS 
	(
	  SELECT
	    line[1]::int8 secret,
	    client
	  FROM
	    regexp_matches(
$$
1
2
3
2024
$$
	    , '[^\r\n]+(?=$|[\r\n])'
	    , 'g'
	    ) WITH ORDINALITY nums(line,client) 
    )
    SELECT 
    	client,
    	secret,
    	null::int2[] AS last_changes,
    	0 AS cnt
    FROM 
    	nums 
    UNION ALL 
    SELECT 
    	client,
    	secret3,
    	(secret3 % 10 - secret % 10)::int2 || last_changes[1:3],
    	cnt + 1 
    FROM 
    	r,
    	LATERAL 
    	(SELECT ((secret * 64) # secret) % 16777216) AS seq1(secret1),
    	LATERAL
     	(SELECT ((secret1 / 32) # secret1) % 16777216) AS seq2(secret2),
     	LATERAL
    	(SELECT ((secret2 * 2048) # secret2) % 16777216) AS seq3(secret3)
    WHERE 
    	cnt < 2000
)
SELECT 
	sum(price)
FROM 
(
SELECT DISTINCT ON (client,last_changes)
	client,
	secret % 10 AS price,
	last_changes
FROM 
	r
WHERE 
	cnt > 3
ORDER BY 
	client,
	last_changes,
	cnt,
	price DESC
 ) AS q 
GROUP BY 
	last_changes
ORDER BY 
	sum(price) DESC 
LIMIT 1;

Получилось ~1.5 раза, 9сек вместо 13

Здравствуйте!

В части №2 решение выбрано для демонстрации возможностей оконок? Вроде как более очевидное и быстрое решение, это иметь массив с последними изменениями внутри рекурсии.

Круто! Спасибо, что причесали мой подход!
И еще спасибо за челлендж! Один бы не полез в эти задачи.. Интересно самому решить, а после сравнить с другим вариантом.

Странно, может буквы убежали при редактировании. У меня результаты 1928 и 6241633730082.

По времени:

Execution Time: 283.704 ms

Execution Time: 467.829 ms

Оставлю тут решение по первой части, чуть быстрее решения Маэстро)

WITH

tbl AS

(

SELECT

a::int,

i

FROM

regexp_split_to_table('2333133121414131402','')

WITH ORDINALITY T(a, i)

),

encoded AS (

SELECT

--разворачиваем, вычисляем значения и нумеруем

(CASE WHEN i % 2 = 1 THEN ((i-1)/2)::TEXT ELSE '.' END) AS a,

ROW_NUMBER() over() n

FROM

tbl,

generate_series(1,a)

)

,

swaps AS

(

SELECT

--координаты точек

UNNEST(array_agg(n) FILTER (WHERE a = '.') ) AS p,

--значения замены с координатами в обратном порядке

UNNEST(array_agg(a::int ORDER BY n DESC) FILTER (WHERE a != '.')) AS d

FROM

encoded e

)

SELECT

--если требуется перестановка, подставляем значения цифры в соответвствующей позиции

sum

((CASE

WHEN s.p IS NOT NULL THEN s.d

ELSE u.a::int

END) * (n - 1))

FROM

encoded AS u

LEFT JOIN swaps AS s ON s.p = u.n,

--кол-во перестановок

(SELECT count(*) AS c FROM swaps WHERE p IS NOT NULL) AS lp,

--общее кол-во элементов

(SELECT count(*) AS c FROM encoded) AS le

WHERE

--точки в конце нас не интересуют

n <= le.c - lp.c

Эх, любите Вы массивы.. Первая часть классическим способом у меня отработала за

Execution Time: 5.862 ms

Ваш вариант отработал за 160.879 ms

Спасибо за интересные варианты решений.

diff AS 
(
SELECT 
	*,
	y - LEAD(y) over(PARTITION BY rn) AS d
FROM 
	t 
),
check_condition AS 
(
SELECT 
	rn
FROM 
	diff
WHERE 
	d IS NOT NULL
GROUP BY 
	rn
HAVING 
	count(*) = ANY(array[(count(*) filter(WHERE d > 0)) , (count(*) filter(WHERE d < 0))])
	AND 
	count(*) = abs(sum(sign(d)) FILTER(WHERE d BETWEEN 1 AND 3 OR d BETWEEN -3 AND -1))
)
SELECT 
	count(*)
FROM 
	check_condition

По второй части размножение колонок через union all будет работать немного быстрее массивов. Агрегировать и сортировать (array_agg) при этом не нужно.

Information

Rating
Does not participate
Registered
Activity

Specialization

Database Developer