<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Backtracking on Kelly Dev</title><link>https://kelly-chui.github.io/tags/backtracking/</link><description>Recent content in Backtracking on Kelly Dev</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Mon, 13 Jul 2026 10:59:57 +0900</lastBuildDate><atom:link href="https://kelly-chui.github.io/tags/backtracking/index.xml" rel="self" type="application/rss+xml"/><item><title>Leetcode 1291. Sequential Digits</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1291-sequential-digits/</link><pubDate>Mon, 13 Jul 2026 10:59:57 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1291-sequential-digits/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/sequential-digits"&gt;https://leetcode.com/problems/sequential-digits&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;low&lt;/code&gt;와 &lt;code&gt;high&lt;/code&gt; 사이의 수 중, 각 자릿수가 123, 3456 처럼 연속으로 이어지는 수를 모두 리턴하는 문제이다&lt;/p&gt;
&lt;p&gt;문제와 제약조건을 보고 바로 DFS 백트래킹로 풀어야겠다는 생각을 했다. 구간의 크기가 최대 1억이기 때문에, 하나하나 확인하는 것은 무리가 있다. 따라서 수를 하나씩 붙여나가면서 확인하고, 조건에 벗어나면 프룬닝 하면 되는 전형적인 문제로 생각했다.&lt;/p&gt;
&lt;p&gt;백트래킹으로도 충분히 빠른 속도로 문제를 풀 수 있지만, 문제를 제출하고 난 뒤 효율성을 검증해보니. &lt;code&gt;high&lt;/code&gt; 크기가 최대 1억이기 때문에, 후보들의 수가 몇개 되지 않기 때문에, 실제로 자리수가 연속되는 모든 숫자들을 만들고 확인하는 방식이 더 빠를수도 있다고 한다.&lt;/p&gt;</description></item><item><title>Programmers. 미로 탈출 명령어</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-maze-escape-commands/</link><pubDate>Sat, 23 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-maze-escape-commands/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/150365"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/150365&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;분명히 배열(문자열)의 원소를 하나씩 채워나가야 하는 DFS 완전 탐색 스타일의 문제인데 k의 최대값이 2,500으로 너무 크다. 하지만 문제에서 주어진 조건들을 읽어보면 프루닝을 통해 백트래킹 문제로 만들 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;현재 위치와 종료 위치 사이의 맨하탄 거리가 남은 이동 횟수보다 적으면, 더 이상 탐색할 필요가 없다.
&lt;ul&gt;
&lt;li&gt;목표에 도달하지 못하는 분기이기 때문에, 분기를 버려야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;남은 이동 횟수와 현재 위치와 종료 위치 사이의 맨하탄 거리의 차가 홀수인 경우에도 더 이상 탐색할 필요가 없다.
&lt;ul&gt;
&lt;li&gt;이동 횟수는 고정이고, 두 위치의 거리보다 크다면 이동 횟수를 어딘가에서 소모해야한다. 그런데 다른 위치로 갔다가, 다시 현재 위치로 돌아올때 소모하는 값은 2이므로, 홀수인 경우에는 목적지에 절대 도달할 수 없게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;마지막으로, 탐색 순서를 잘 정했다면 처음으로 성공한 케이스가 곧 사전순에서 가장 앞선 순서가 된다. 한 번만 성공하게 되면 그 뒤의 모든 분기는 의미가 없어진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이렇게 프루닝을 하면 완전 탐색으로 절대로 해결 불가능한 문제를 풀 수 있게 된다.&lt;/p&gt;</description></item><item><title>Programmers. 불량 사용자</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-bad-user/</link><pubDate>Mon, 21 Jul 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-bad-user/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/64064"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/64064&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;일정 크기의 배열(혹은 컬렉션)을 만들어서 매칭되는지 확인해야 하는 문제다.&lt;/p&gt;
&lt;p&gt;DFS를 사용해서 모든 경우의 수를 만들기는 쉽지만, 그 경우의 수가 문제에서 제시하는 조건에 맞는지 확인하는 것은 어렵다. 따라서 알고리즘을 약간 수정해서 좀 더 효율적이고 만들기 쉬운 알고리즘을 만들어야 한다.&lt;/p&gt;
&lt;p&gt;알고리즘은 다음과 같다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;주어진 &lt;code&gt;banned_id&lt;/code&gt; 배열 원소 하나하나에 대응가능한 id를 &lt;code&gt;user_id&lt;/code&gt;에서 뽑아서 후보 &lt;code&gt;set&lt;/code&gt;에 넣는다.&lt;/li&gt;
&lt;li&gt;1번을 재귀적으로 진행한다. &lt;code&gt;set&lt;/code&gt;에 담는 이유는 id가 중복되면 안되기 때문이다.&lt;/li&gt;
&lt;li&gt;후보 set이 완성되면, 정답 &lt;code&gt;set&lt;/code&gt;에 저장한다. &lt;code&gt;set&lt;/code&gt;은 &lt;code&gt;set&lt;/code&gt;에 담을 수 없으므로 &lt;code&gt;frozenset&lt;/code&gt;을 이용한다.&lt;/li&gt;
&lt;li&gt;정답 &lt;code&gt;set&lt;/code&gt;의 개수를 리턴한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strB&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strB&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strB&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;*&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidateSet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idSet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;idSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;frozenset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidateSet&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;candidateSet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidateSet&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;idSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;idSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="n"&gt;idSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item></channel></rss>