<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>zo_neutron.log</title>
        <link>https://velog.io/</link>
        <description>정진하는 개발자</description>
        <lastBuildDate>Sun, 26 Mar 2023 08:31:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>zo_neutron.log</title>
            <url>https://velog.velcdn.com/images/zo_neutron/profile/67774d6b-438e-4de1-bf31-6a1957c71471/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. zo_neutron.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/zo_neutron" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Rust] 교점에 별 만들기]]></title>
            <link>https://velog.io/@zo_neutron/Rust-%EA%B5%90%EC%A0%90%EC%97%90-%EB%B3%84-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@zo_neutron/Rust-%EA%B5%90%EC%A0%90%EC%97%90-%EB%B3%84-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Sun, 26 Mar 2023 08:31:24 GMT</pubDate>
            <description><![CDATA[<h1 id="rust-교점에-별-만들기">[Rust] 교점에 별 만들기</h1>
<p>프로그래머스는 Rust 언어를 지원하지 않아, 해당 코드는 정답을 돌려본 것이 아닌 Java로 푼 문제로 Rust로 바꿔 풀어본 코드입니다.</p>
<h2 id="문제-요약">문제 요약</h2>
<p><code>Ax + By + C = 0</code>으로 표현할 수 있는 <code>n</code>개의 직선이 주어질 때, 이 직선의 교점 중 정수 좌표에 별을 그리려 합니다.</p>
<p>직선 <code>A, B, C</code>에 대한 정보가 담긴 배열 <code>line</code>이 매개변수로 주어집니다. 이때 모든 별을 포함하는 최소 사각형을 return 하도록 solution 함수를 완성해주세요.</p>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>line의 세로(행) 길이는 2 이상 1,000 이하인 자연수입니다.<ul>
<li>line의 가로(열) 길이는 3입니다.</li>
<li>line의 각 원소는 [A, B, C] 형태입니다.</li>
<li>A, B, C는 -100,000 이상 100,000 이하인 정수입니다.</li>
<li>무수히 많은 교점이 생기는 직선 쌍은 주어지지 않습니다.</li>
<li>A = 0이면서 B = 0인 경우는 주어지지 않습니다.</li>
</ul>
</li>
<li>정답은 1,000 * 1,000 크기 이내에서 표현됩니다.</li>
<li>별이 한 개 이상 그려지는 입력만 주어집니다.</li>
</ul>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>line</th>
<th>result</th>
</tr>
</thead>
<tbody><tr>
<td><code>[[2, -1, 4], [-2, -1, 4], [0, -1, 1], [5, -8, -12], [5, 8, 12]]</code></td>
<td><code>[&quot;....*....&quot;, &quot;.........&quot;, &quot;.........&quot;, &quot;*.......*&quot;, &quot;.........&quot;, &quot;.........&quot;, &quot;.........&quot;, &quot;.........&quot;, &quot;*.......*&quot;]</code></td>
</tr>
<tr>
<td><code>[[0, 1, -1], [1, 0, -1], [1, 0, 1]]</code></td>
<td><code>[&quot;*.*&quot;]</code></td>
</tr>
<tr>
<td><code>[[1, -1, 0], [2, -1, 0]]</code></td>
<td><code>[&quot;*&quot;]</code></td>
</tr>
<tr>
<td><code>[[1, -1, 0], [2, -1, 0], [4, -1, 0]]</code></td>
<td><code>[&quot;*&quot;]</code></td>
</tr>
</tbody></table>
<h3 id="참고-사항">참고 사항</h3>
<p><code>Ax + By + E = 0</code>
<code>Cx + Dy + F = 0</code>
두 직선의 교점이 유일하게 존재할 경우, 그 교점은 다음과 같습니다.</p>
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/133f75ab-a22a-476b-92c2-587cea721944/RisingStarExpression.png" alt="RisingStarExpression.png"></p>
<p>또, AD - BC = 0인 경우 두 직선은 평행 또는 일치합니다.</p>
<p>문제 링크 : <a href="https://school.programmers.co.kr/learn/courses/30/lessons/87377">https://school.programmers.co.kr/learn/courses/30/lessons/87377</a></p>
<h2 id="풀이">풀이</h2>
<h3 id="풀이법">풀이법</h3>
<ul>
<li>별도의 알고리즘이 있는 것이 아닌, 단순히 주어진 식을 적용해서 교점을 찾아 리스트에 적용해둔 후, 문자열로 변환하는 문제였다.</li>
<li>풀이 순서<ol>
<li>입력으로 주어진 입력들의 모든 조합을 탐색</li>
<li>조합을 탐색하면서 두 직선간의 정수 교점을 찾아 리스트에 저장하며, 격자판의 필요 크기를 조정해 나아감</li>
<li>격자판에 리스트에 저장된 교점들을 표시</li>
<li>격자판을 탐색하면서, 교점의 위치에서는 <code>*</code>을 아닌 곳에서는 <code>.</code>으로 문자열을 생성한 다음 print 수행</li>
</ol>
</li>
</ul>
<h3 id="코드">코드</h3>
<pre><code class="language-rust">use std::cmp::min;
use std::cmp::max;

fn main() {

    println!(&quot;sol 1&quot;);
    solution(vec![[2, -1, 4], [-2, -1, 4], [0, -1, 1], [5, -8, -12], [5, 8, 12]]);

    println!(&quot;sol 2&quot;);
    solution(vec![[0, 1, -1], [1, 0, -1], [1, 0, 1]]);

    println!(&quot;sol 3&quot;);
    solution(vec![[1, -1, 0], [2, -1, 0]]);

    println!(&quot;sol 4&quot;);
    solution(vec![[1, -1, 0], [2, -1, 0], [4, -1, 0]]);


}

fn solution(line: Vec&lt;[i64;3]&gt; ){

    let (mut max_x,mut min_x,mut max_y,mut min_y) = (i64::MIN, i64::MAX, i64::MIN, i64::MAX);

    let mut points: Vec&lt;[i64;2]&gt; = Vec::new();

    // 1. 입력으로 주어진 입력들의 모든 조합을 탐색
    for i in 0..line.len()-1 {
        for j in i+1..line.len(){
            // 2. 조합을 탐색하면서 두 직선간의 정수 교점을 찾아 리스트에 저장하며, 격자판의 필요 크기를 조정해 나아감
            let (a, b, e) = (line[i][0], line[i][1], line[i][2]);
            let (c, d, f) = (line[j][0], line[j][1], line[j][2]);

            let numerator_x = b*f - e*d;
            let numerator_y = e*c - a*f;
            let denominator = a*d - b*c;

            // 교점이 없는 경우 pass
            if denominator == 0{
                continue;
            }
            // 정수인 교점만을 골라내어 탐색
            if numerator_x % denominator == 0 &amp;&amp; numerator_y % denominator == 0{

                let point: [i64;2] = [numerator_x/denominator, numerator_y/denominator];
                points.push(point);

                max_x = max(max_x, point[0]);
                min_x = min(min_x, point[0]);
                max_y = max(max_y, point[1]);
                min_y = min(min_y, point[1]);
            }
        }
    }

    // i64 =&gt; usize로 형변환. 격자판의 필요 크기를 구함
    let range_x:usize = (max_x - min_x +1).try_into().unwrap();
    let range_y:usize = (max_y - min_y +1).try_into().unwrap();

    // 격자판 생성
    // array는 compile 시에 size가 정해져 있어야 함으로, constant value가 아닌 값으로 생성 X. =&gt; 대신 vec 사용
    let mut is_pointed  = vec![vec![false;range_x] ; range_y];

    // 3. 격자판에 리스트에 저장된 교점들을 표시
    for point in points {
        let x: usize = (point[0]-min_x).try_into().unwrap();
        let y: usize = (max_y-point[1]).try_into().unwrap();
        is_pointed[y][x] = true;
    }


    // 정답 반환할 answer 리스트 생성
    let mut answer:Vec&lt;String&gt; =  Vec::with_capacity(range_y);

    // 4. 격자판을 탐색하면서, 교점의 위치에서는 `*`을 아닌 곳에서는 `.`으로 문자열을 생성한 다음 print 수행
    for row in is_pointed {
        let mut string_line = String::with_capacity(range_x);
        for col in row {
            if col {
                string_line.push_str(&quot;*&quot;);
            }else {
                string_line.push_str(&quot;.&quot;);
            }
        }
        answer.push(string_line);
    }

    for row in answer {
        println!(&quot;{}&quot;, row);
    }

} 
</code></pre>
<h2 id="학습한-내용">학습한 내용</h2>
<ol>
<li><p><code>Vec</code> 선언 및 요소의 추가</p>
<ul>
<li><p><code>Vec</code> 선언의 3가지 방법</p>
<ul>
<li><p>빈 Vector 선언 (feat. 2차원)</p>
<pre><code class="language-rust">let mut vector: Vec&lt;[i64;2]&gt; = Vec::new(); // 2차원 선언</code></pre>
</li>
<li><p>값으로 선언</p>
<pre><code class="language-rust">  let vector: Vec&lt;[i64;3]&gt; = vec![[2, -1, 4], [-2, -1, 4], [0, -1, 1], [5, -8, -12], [5, 8, 12]]; </code></pre>
</li>
<li><p>배열의 용량 지정하며 선언</p>
<pre><code class="language-rust">let vector:Vec&lt;String&gt; =  Vec::with_capacity(n); // n 만큼의 배열 용량 미리 지정</code></pre>
<ul>
<li><code>capacity</code>의 지정은 Vec의 길이(len)과는 상관 없으며, 단순히 memory에서의 공간은 n만큼 할당해 두는 것이다.</li>
<li>다시 말해, vector의 용량을 n만큼 미리 확보해 둠으로써, n개의 요소까지는 vector에 추가되어도 메모리 재할당이 일어나지 않게 된다.</li>
</ul>
</li>
</ul>
</li>
<li><p><code>Vec</code>에 요소 추가</p>
<pre><code class="language-rust">vector.push(element); // 요소 추가</code></pre>
</li>
</ul>
</li>
<li><p>array는 compile 시에 size가 정해져 있어야 함으로, constant value가 아닌 값으로 생성할 수 없다.</p>
<ul>
<li><p>위의 코드에서 2차원 배열을 선언할 때, 아래 코드를 사용시 컴파일 에러가 나게 된다.</p>
<pre><code class="language-rust">  let range_x:usize = (max_x - min_x +1).try_into().unwrap();
  let range_y:usize = (max_y - min_y +1).try_into().unwrap();

  let mut is_pointed  = [[false;range_x] ; range_y]; // 컴파일 에러</code></pre>
</li>
</ul>
</li>
<li><p>indexing에는 <code>usize</code> 타입의 변수만 사용가능하면, 형변환에 사용되는 <code>TryInto</code> trait의 <code>try_into()</code> 가 사용된다. </p>
<ul>
<li><p><code>TryInto</code> 정의</p>
<pre><code class="language-rust">pub trait TryInto&lt;T&gt;: Sized {
    type Error;

    fn try_into(self) -&gt; Result&lt;T, Self::Error&gt;;
}</code></pre>
</li>
<li><p><code>try_into</code>는 self를 소비( consume)하기 때문에, <code>try_into</code>로 형변환시 더 이상 기존 변수는 사용할 수 없게 된다.</p>
</li>
<li><p>또한 <code>Result</code>를 반환하기에 값을 얻고 싶다면 <code>unwrap()</code>을 사용해야 된다.</p>
</li>
</ul>
</li>
</ol>
]]></description>
        </item>
    </channel>
</rss>