<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: hackem</title>
    <description>The latest articles on DEV Community by hackem (@hackem).</description>
    <link>https://dev.to/hackem</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F896006%2Fafb92c40-f430-4b71-a36f-7614eedef29b.png</url>
      <title>DEV Community: hackem</title>
      <link>https://dev.to/hackem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hackem"/>
    <language>en</language>
    <item>
      <title>Meta Hacker Cup - Questions A, B1, C1</title>
      <dc:creator>hackem</dc:creator>
      <pubDate>Wed, 31 Aug 2022 03:40:38 +0000</pubDate>
      <link>https://dev.to/hackem/meta-hacker-cup-questions-a-b1-c1-57a7</link>
      <guid>https://dev.to/hackem/meta-hacker-cup-questions-a-b1-c1-57a7</guid>
      <description>&lt;p&gt;Since the explanations on the official website are sufficiently clear, I will post only the code solutions without any conceptual origination.&lt;/p&gt;

&lt;h2&gt;
  
  
  A: Second Hands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sys

sys.stdin = open('second_hands_input.txt', 'r')

C = int(sys.stdin.readline())
res =[]
for i in range(C):
    arr = [int(x) for x in sys.stdin.readline().split()]
    N, T = arr[0], arr[1]
    S = [int(x) for x in sys.stdin.readline().split()]
    if N &amp;gt; (T*2):
        res.append(False)
        continue
    more_than_twice = False
    hist = {}
    for el in S:
       if el in hist:
           hist[el] += 1
       else:
           hist[el] = 1
       if hist[el] &amp;gt; 2:
           more_than_twice = True
           break
    res.append(not(more_than_twice))
    print(res)
sys.stdout = open('output.txt', 'w')
for i in range(C):
    if res[i]:
        sys.stdout.write(f'Case #{i+1}: YES')
        if i&amp;lt;C-1:
            sys.stdout.write('\n')
    else:
        sys.stdout.write(f'Case #{i+1}: NO')
        if i&amp;lt;C-1:
            sys.stdout.write('\n')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  B1: Second Friend
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sys
sys.stdin = open('second_friend_input.txt', 'r')
sys.stdout = open('output.txt', 'w')
N = int(sys.stdin.readline())
for n in range(N):
    sudo = [int(x) for x in sys .stdin.readline().split()]
    R, C = sudo[0], sudo[1]
    tree_present = False
    for r in range(R):
        arr = list(sys.stdin.readline())
        for c in range(C):
            if arr[c] == '^':
                tree_present = True
                break
    if tree_present:
        if (R&amp;lt;2) or (C&amp;lt;2):
            sys.stdout.write(f'Case #{n+1}: Impossible')
            sys.stdout.write('\n')
        else:
            sys.stdout.write(f'Case #{n+1}: Possible')
            for i in range(R):
                sys.stdout.write('\n')
                for i in range(C):
                    sys.stdout.write('^')
            sys.stdout.write('\n')

    else:
        sys.stdout.write(f'Case #{n+1}: Possible')
        for i in range(R):
                sys.stdout.write('\n')
                for i in range(C):
                    sys.stdout.write('.')
        sys.stdout.write('\n')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  C1: Second Meaning
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sys
sys.stdin = open('second_meaning_input.txt', 'r')
sys.stdout = open('output_final.txt', 'w')
T = int(sys.stdin.readline())
for t in range(T):
    res = []
    N = int(sys.stdin.readline())
    c = sys.stdin.readline()
    sys.stdout.write(f'Case #{t+1}:')
    sys.stdout.write('\n')
    first_code = c[0]
    if first_code == '.':
        for n in range(N-1):
            c = '-' + c
            sys.stdout.write(f'{c}')
    else:
        for n in range(N-1):
            c = '.' + c
            sys.stdout.write(f'{c}')


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Remarks
&lt;/h2&gt;

&lt;p&gt;These were the questions I did for the qualification rounds. Will try to upload the other question solutions before the next round commences for practice sake. &lt;/p&gt;

</description>
      <category>competitiveprogramming</category>
      <category>algorithms</category>
      <category>riddles</category>
    </item>
    <item>
      <title>Word Break</title>
      <dc:creator>hackem</dc:creator>
      <pubDate>Mon, 15 Aug 2022 15:03:30 +0000</pubDate>
      <link>https://dev.to/hackem/word-break-2kj5</link>
      <guid>https://dev.to/hackem/word-break-2kj5</guid>
      <description>&lt;h2&gt;
  
  
  Problem Description
&lt;/h2&gt;

&lt;p&gt;Given a string s and a dictionary of strings wordDict, return true if s can be segmented into a space-separated sequence of one or more dictionary words.&lt;/p&gt;

&lt;p&gt;Note that the same word in the dictionary may be reused multiple times in the segmentation.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
Input: s = "leetcode", wordDict = ["leet","code"]&lt;br&gt;
Output: true&lt;br&gt;
Explanation: Return true because "leetcode" can be segmented as "leet code".&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
Input: s = "catsandog", wordDict =["cats","dog","sand","and","cat"]&lt;br&gt;
Output: false&lt;/p&gt;
&lt;h2&gt;
  
  
  Concept
&lt;/h2&gt;

&lt;p&gt;It is rather straightforward or 'human-like' to brute force this problem. To segment &lt;em&gt;s&lt;/em&gt;, we simply check if we can create a joint of words in wordDict to create &lt;em&gt;s&lt;/em&gt;. A simple approach would be to check whether for each segment in &lt;em&gt;s&lt;/em&gt; there is a match in &lt;em&gt;wordDict&lt;/em&gt;. If the segment is a match, it also has to have a connected path of matched segments until the end of &lt;em&gt;s&lt;/em&gt; . Example: It is not enough that 'cats' and 'and' (from &lt;em&gt;wordDict&lt;/em&gt;) are matches in 'catsandog' if we do not find a match for segment 'og'.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://www.programiz.com/dsa/dynamic-programming"&gt;dynamic programming&lt;/a&gt; solution is applicable here as we are creating a new subproblem each time we find a segment matching in &lt;em&gt;s&lt;/em&gt;, the subproblem is &lt;em&gt;s&lt;/em&gt; minus the matched segment. Our base case being an empty &lt;em&gt;s&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I did a recursive approach by starting from the beginning of &lt;em&gt;s&lt;/em&gt;. The function then breaks off into all subproblems created by all matchings in &lt;em&gt;s&lt;/em&gt; and returns True if one subproblem reaches an empty &lt;em&gt;s&lt;/em&gt;, i.e. all parts of &lt;em&gt;s&lt;/em&gt; matched. I tried this solution however I got a Time Limit Exceeded. I then chanced upon a clever trick in the leetcode discussions section to save computational time.&lt;/p&gt;

&lt;p&gt;For this solution, we create a dp array for all indices of &lt;em&gt;s&lt;/em&gt; plus one for the base case. Set all value of the array to False except our base case. Then we iterate from the end of &lt;em&gt;s&lt;/em&gt; checking for each element whether it is a match and whether that match is connected to the end by checking dp[i + len(matched_word)]. The advantage of this method is that we save computational time by caching our results.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;My initial solution, recursion&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Solution:
    def wordBreak(self,s, wordDict, i=0):
        res = []
        for w in wordDict:
            if (i+len(w))&amp;lt;=len(s) and (s[i:i+len(w)]==w):
                if i+len(w) == len(s): return True
                else:
                    res.append(self.wordBreak(s[i+len(w):],wordDict))
        if True in res:
            return True
        return False


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The bottom-up dp caching solution&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -&amp;gt; bool:
        dp = [False] * (len(s) + 1)
        dp[len(s)] = True
        for i in range(len(s)-1,-1,-1):
            for w in wordDict:
                if ((i+len(w))&amp;lt;=len(s)) and (s[i:i+len(w)]==w):
                    dp[i] = dp[i+len(w)]
                if dp[i]:
                    break
        return dp[0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Remarks
&lt;/h2&gt;

&lt;p&gt;This problem appeared uncomplicated but had an interesting elusiveness that made it different from other dp problems. The solutions remind us to consider computational time beyond just time complexity. Both solutions were 

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;O(n2∗m)O(n^2*m)&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;∗&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;m&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;where n is the length of &lt;em&gt;s&lt;/em&gt; and m the length of &lt;em&gt;wordDict&lt;/em&gt;. Yet, only the caching solution was accepted. Remarkception, still trying to figure out dev.to's mathematical text support, currently using katex.&lt;/p&gt;

</description>
      <category>leetcode</category>
      <category>algorithms</category>
      <category>competitiveprogramming</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Longest Increasing Subsequence</title>
      <dc:creator>hackem</dc:creator>
      <pubDate>Sat, 13 Aug 2022 15:48:06 +0000</pubDate>
      <link>https://dev.to/hackem/longest-increasing-subsequence-255b</link>
      <guid>https://dev.to/hackem/longest-increasing-subsequence-255b</guid>
      <description>&lt;h2&gt;
  
  
  Problem Description
&lt;/h2&gt;

&lt;p&gt;Given an integer array &lt;em&gt;nums&lt;/em&gt;, return the length of the longest &lt;strong&gt;strictly&lt;/strong&gt; increasing subsequence. &lt;/p&gt;

&lt;p&gt;A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements. For example, [3,6,2,7] is a subsequence of the array [0,3,1,6,2,2,7].&lt;/p&gt;

&lt;h2&gt;
  
  
  Concept
&lt;/h2&gt;

&lt;p&gt;A brute force method is applied by simply making all possible increasing subsequences from the zeroth index then keeping all of them in memory and eventually returning the longest among the candidate lists. This approach has an O(&lt;em&gt;n&lt;/em&gt;^2) time complexity where &lt;em&gt;n&lt;/em&gt; is the length of the array. This is due to &lt;em&gt;n&lt;/em&gt; number of permutations from the zeroth index with each permutation requiring at worst n number of checks (to form the subsequence). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WLg6V1r---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ieetjvrv45u8o4x6sps2.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WLg6V1r---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ieetjvrv45u8o4x6sps2.jpeg" alt="Example Brute Force Longest Increasing Subsequence" width="880" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the brute force method it is obvious that there are potential improvements if we take into account that we want to keep the elements in the subsequence as small as we can before we increment another element. For example: we would obviously discard the 3 in [0,3] for our next element if it is smaller than 3 as it increases the range of numbers we can get for our next larger element, i.e., [0,1] is better than [0,3]. If we apply the same concept not only to the last number in our current subsequence but to all the numbers in the subsequence we will then be able to increase the range of possible numbers in all positions in the subsequence. Hence, we will be creating and maintaining the longest increasing subsequence throughout the loop. Our algorithm would work like so: 1. If the next element is larger than the last element in our subsequence, append it to subsequence. 2. Else, find the biggest number in the subsequence the element can replace such that the number is smaller than the element and replacing the number with the element maintains the incremental condition of the subsequence. I know this sounds confusing, the example will illustrate the concept better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B5RV5oPj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ckgyrfnoga5evu3xtwzy.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B5RV5oPj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ckgyrfnoga5evu3xtwzy.jpeg" alt="LIS: Longest Increasing Subsequence, Bcs; because" width="880" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice a couple of things from this example. Firstly, the final longest increasing subsequence is not an existent valid subsequence in &lt;em&gt;nums&lt;/em&gt;. Fortunately, the problem requires only to return the length of the subsequence. Secondly, we guarantee the past existence of a valid subsequence after we substituted an element in the subsequence with the next element so long as the next element is smaller than the past element. Example: The 5th iteration produces subsequence [1,2,6] although this is not derivable from &lt;em&gt;nums&lt;/em&gt;, we certainly know such a a valid subsequence existed, [4,5,6] from the third iteration. Hence, it also stands to reason that the existence of [1,2,6,7,8], a non-existent subsequence, guaranteed a past valid subsequence that fulfils our condition of incrementation, in this example is [4,5,6,7,8]. These two observations show us that the algorithm does not produce false subsequences. To illustrate the power of the algorithm see the following example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6MS28MCf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3f4flnbo5uvazasl6h27.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6MS28MCf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3f4flnbo5uvazasl6h27.jpeg" alt="LIS: Longest Increasing Subsequence, Bcs; because" width="880" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that by finding the smallest possible number to occupy each index we are maximising the range of numbers we can find. Although we could have created the longest increasing subsequence similarly by our elements in the 3rd iteration, [4,5,6], by minimising the elements such as in the 6th iteration we increase the potential of our subsequence as the next element needs to only be bigger than 3, not 6. Understand that we can only place 3 at the 6th iteration because the element before 3 is 2 and not 5, highlighting the importance of minimising the number in all indices due to the domino effect.&lt;/p&gt;

&lt;p&gt;The algorithm keeps a current longest increasing subsequence at each iteration and iterates once throughout the list. To find the position of our next element in the current subsequence we do a binary search. Hence, the time complexity of the algorithm is O(n*log(n)). &lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;We create a variable &lt;em&gt;tmp&lt;/em&gt; to keep track of the current longest increasing subsequence. We then loop over each element in &lt;em&gt;nums&lt;/em&gt;. In each iteration we check whether, upon insertion, the element will be the largest element or not. This check is done by bisect_left which accept the sorted list &lt;em&gt;tmp&lt;/em&gt; and a number &lt;em&gt;x&lt;/em&gt; and returns the position &lt;em&gt;x&lt;/em&gt; occupies in &lt;em&gt;tmp&lt;/em&gt; so that &lt;em&gt;tmp&lt;/em&gt; maintains sorted. The function bisect_left uses a binary search. If the element is the biggest then bisect_left will return the last index of the newly appended &lt;em&gt;a&lt;/em&gt; which is which is equals to len(temp). As we established, if the element, &lt;em&gt;n&lt;/em&gt;, is the biggest we append it, else, we find the smallest element that is bigger than &lt;em&gt;n&lt;/em&gt; in &lt;em&gt;tmp&lt;/em&gt; and replace it with &lt;em&gt;n&lt;/em&gt;, bisect_left returns the index to be replaced. Finally we return the variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def lengthOfLIS(self, nums: List[int]) -&amp;gt; int:
        N = len(nums)
        tmp = [nums[0]]
        for n in nums:
            x = bisect_left(tmp,n)
            if x == len(tmp):
                tmp.append(n)
            else:
                tmp[x] = n
        return len(tmp)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Real-life application of the Longest Increasing Subsequence Algorithm
&lt;/h2&gt;

&lt;p&gt;Part of Maximum Unique Match Finder for aligning entire genomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remarks
&lt;/h2&gt;

&lt;p&gt;Surprisingly, the algorithm to find the longest increasing subsequence, not merely its length, also has a time complexity of O(n*log(n)). The algorithm is inspired by the card game Patience or Klondike. Here's a great resource to learn about &lt;a href="https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/LongestIncreasingSubsequence.pdf"&gt;Patience Sort&lt;/a&gt;. Funnily enough, during my Police Officer Basic Course I sat beside my friend who would play Klondike throughout class, it was one of the few games available on our issued laptops.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>leetcode</category>
      <category>competitiveprogramming</category>
      <category>computerscience</category>
    </item>
  </channel>
</rss>
