diff --git a/404.html b/404.html index 10f54f9..5c8b5a6 100644 --- a/404.html +++ b/404.html @@ -13,13 +13,13 @@ - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/CNAME b/CNAME deleted file mode 100644 index 4c91a2c..0000000 --- a/CNAME +++ /dev/null @@ -1 +0,0 @@ -blog.mfocko.xyz \ No newline at end of file diff --git a/assets/js/2523321d.50613303.js b/assets/js/2523321d.54e7755c.js similarity index 99% rename from assets/js/2523321d.50613303.js rename to assets/js/2523321d.54e7755c.js index 470fc9f..ffc2e27 100644 --- a/assets/js/2523321d.50613303.js +++ b/assets/js/2523321d.54e7755c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9193],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),u=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return i.createElement(s.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},d=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=u(n),d=a,k=m["".concat(s,".").concat(d)]||m[d]||c[d]||r;return n?i.createElement(k,o(o({ref:t},p),{},{components:n})):i.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[m]="string"==typeof e?e:a,o[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>r,metadata:()=>l,toc:()=>u});var i=n(7462),a=(n(7294),n(3905));const r={id:"seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n"},o="8th seminar bonus assignment",l={unversionedId:"bonuses/seminar-08",id:"bonuses/seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n",source:"@site/pb071/bonuses/08.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-08",permalink:"/pb071/bonuses/seminar-08",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/08.md",tags:[],version:"current",lastUpdatedAt:1694108971,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n"},sidebar:"autogeneratedBar",previous:{title:"5th and 6th seminar",permalink:"/pb071/bonuses/seminar-05-06"},next:{title:"10th seminar",permalink:"/pb071/bonuses/seminar-10"}},s={},u=[{value:"Introduction",id:"introduction",level:2},{value:"Warning",id:"warning",level:2},{value:"Testing",id:"testing",level:2},{value:"Task no. 1: Counting (0.75 K\u20a1)",id:"task-no-1-counting-075-k",level:2},{value:"Requirements",id:"requirements",level:3},{value:"Bonus part (0.75 K\u20a1)",id:"bonus-part-075-k",level:3},{value:"Task no. 2: Weird trees (1 K\u20a1)",id:"task-no-2-weird-trees-1-k",level:2},{value:"Submitting",id:"submitting",level:2}],p={toc:u},m="wrapper";function c(e){let{components:t,...r}=e;return(0,a.kt)(m,(0,i.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"8th-seminar-bonus-assignment"},"8th seminar bonus assignment"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/08.tar.gz"},"Source")),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"In this bonus you can implement two tasks, one of them has a bonus part with generic\nsolution."),(0,a.kt)("p",null,"One is focused on counting ananas or in case of generic version any substring in\nthe file, but with a restriction on the function you use."),(0,a.kt)("p",null,"Other one has a more algorithmic spirit."),(0,a.kt)("p",null,"For this bonus you can get at maximum 2.5 K\u20a1."),(0,a.kt)("h2",{id:"warning"},"Warning"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"DO NOT COMMIT test data")," to your own git repository, since the tests include\nfiles that exceed 10MB by themselves. Even if they are on separate branch, they\ntake up the space."),(0,a.kt)("h2",{id:"testing"},"Testing"),(0,a.kt)("p",null,"For testing you are provided with python script (requires ",(0,a.kt)("inlineCode",{parentName:"p"},"click")," to be installed:\n",(0,a.kt)("inlineCode",{parentName:"p"},"pip3 install --user click"),") and ",(0,a.kt)("inlineCode",{parentName:"p"},"Makefile")," that provides following targets:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check-counting")," - runs the ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," tests"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check-counting-bonus")," - runs the ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," tests with bonus implemented"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check")," - runs both ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"counting-bonus")," tests"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"clean")," - removes output files from the test runs")),(0,a.kt)("h2",{id:"task-no-1-counting-075-k"},"Task no. 1: Counting (0.75 K\u20a1)"),(0,a.kt)("p",null,"Your first task is to make smallish program that counts occurences of specific\n(or given) word from file and writes the number to other file."),(0,a.kt)("p",null,"Usage of the program is:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"Usage: ./counting [string-to-be-counted]\n")),(0,a.kt)("p",null,"Arguments that are passed to the program represent:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"")," - path to the file where we count the words"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"")," - path to the file where we output the count"),(0,a.kt)("li",{parentName:"ul"},"(optional argument) ",(0,a.kt)("inlineCode",{parentName:"li"},"[string-to-be-counted]")," - in case you implement bonus,\notherwise we default to word ",(0,a.kt)("inlineCode",{parentName:"li"},"ananas")," ;)")),(0,a.kt)("p",null,"In skeleton you are given 3 empty, but documented, functions to implement."),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"count_anything")," - function accepts input file and substring to be counted in\nthe file, returns the count."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"count_ananas")," - same as ",(0,a.kt)("inlineCode",{parentName:"li"},"count_anything"),", but specialized for ananases, the\ndefault implementation from the skeleton expects you to implement ",(0,a.kt)("inlineCode",{parentName:"li"},"count_anything"),"\nand therefore it just calls the other function."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"write_number")," - function that writes the number to the file, why would you\nneed the function is explained later :)")),(0,a.kt)("h3",{id:"requirements"},"Requirements"),(0,a.kt)("p",null,"For manipulation with the files you are only allowed to use ",(0,a.kt)("inlineCode",{parentName:"p"},"fopen"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"fclose"),",\n",(0,a.kt)("inlineCode",{parentName:"p"},"fgetc")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"fputc"),". Functions like ",(0,a.kt)("inlineCode",{parentName:"p"},"fprintf")," (except for ",(0,a.kt)("inlineCode",{parentName:"p"},"stderr")," or logging) and\n",(0,a.kt)("inlineCode",{parentName:"p"},"fscanf")," are ",(0,a.kt)("strong",{parentName:"p"},"forbidden"),"."),(0,a.kt)("p",null,"In case you struggle and want to use one of those functions, the solution will be\npenalized by 50% of points."),(0,a.kt)("h3",{id:"bonus-part-075-k"},"Bonus part (0.75 K\u20a1)"),(0,a.kt)("p",null,"Bonus part of this assignment is to implement ",(0,a.kt)("inlineCode",{parentName:"p"},"count_anything")," rather than ",(0,a.kt)("inlineCode",{parentName:"p"},"count_ananas"),"."),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Smaller hint: This task does not need dynamic allocation :) You just need one\ngood helper function and the right idea ;)")),(0,a.kt)("h2",{id:"task-no-2-weird-trees-1-k"},"Task no. 2: Weird trees (1 K\u20a1)"),(0,a.kt)("p",null,"In this task we are crossing our paths with ",(0,a.kt)("em",{parentName:"p"},"algorithms and data structures"),".\nYour task is to write a program that constructs tree from the file that is given\nas an argument and pretty-prints it."),(0,a.kt)("p",null,"Input file consists of lines, that include ",(0,a.kt)("inlineCode",{parentName:"p"},"key")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"rank")," in form ",(0,a.kt)("inlineCode",{parentName:"p"},"key;rank"),"\nor ",(0,a.kt)("inlineCode",{parentName:"p"},"nil"),". Why would we have ",(0,a.kt)("inlineCode",{parentName:"p"},"nil")," in a file? The file represents pre-order iteration\nthrough the tree. Leaves never have rank different than 0, so you can safely assume\n2 non-existing ",(0,a.kt)("inlineCode",{parentName:"p"},"nil"),"s in the input after you read such node ;)"),(0,a.kt)("table",null,(0,a.kt)("tr",null,(0,a.kt)("th",null,"Example input file"),(0,a.kt)("th",null,"Tree it represents")),(0,a.kt)("tr",null,(0,a.kt)("td",null,(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"8;4\n5;3\n3;2\n2;1\n1;0\nnil\n4;0\n7;1\n6;0\nnil\n11;2\n10;1\n9;0\nnil\n12;0\n"))),(0,a.kt)("td",null,(0,a.kt)("p",null,(0,a.kt)("img",{alt:"tree",src:n(4860).Z,width:"633",height:"684"}))))),(0,a.kt)("p",null,"In this task you are only provided with different trees in the ",(0,a.kt)("inlineCode",{parentName:"p"},"test-trees")," directory.\nImplementation and format of the pretty-print is totally up to you. :)"),(0,a.kt)("p",null,"Example of mine for the tree above:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"8 (rank = 4)\n+-- 5 (rank = 3)\n| +-- 3 (rank = 2)\n| | +-- 2 (rank = 1)\n| | | +-- 1 (rank = 0)\n| | +-- 4 (rank = 0)\n| +-- 7 (rank = 1)\n| +-- 6 (rank = 0)\n+-- 11 (rank = 2)\n +-- 10 (rank = 1)\n | +-- 9 (rank = 0)\n +-- 12 (rank = 0)\n")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Can you find out what are those trees? :)")),(0,a.kt)("h2",{id:"submitting"},"Submitting"),(0,a.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Ideally submit the assignment through the merge request. Step-by-step tutorial is\npresent ",(0,a.kt)("a",{parentName:"p",href:"../mr"},"here"),". For setting assignee my xlogin is ",(0,a.kt)("inlineCode",{parentName:"p"},"xfocko"),"."),(0,a.kt)("p",null,"In case you do not want to experiment on GitLab, send me the source code via email,\nbut please prefix subject with: ",(0,a.kt)("inlineCode",{parentName:"p"},"[PB071/14][seminar-08]")),(0,a.kt)("p",null,"Deadline for the submission of the bonus is ",(0,a.kt)("strong",{parentName:"p"},"May 4th 24:00"),"."))}c.isMDXComponent=!0},4860:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/tree-c9e37f87f9095c00fad33ea034485ce6.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[9193],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),u=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return i.createElement(s.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},d=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),m=u(n),d=a,k=m["".concat(s,".").concat(d)]||m[d]||c[d]||r;return n?i.createElement(k,o(o({ref:t},p),{},{components:n})):i.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[m]="string"==typeof e?e:a,o[1]=l;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>r,metadata:()=>l,toc:()=>u});var i=n(7462),a=(n(7294),n(3905));const r={id:"seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n"},o="8th seminar bonus assignment",l={unversionedId:"bonuses/seminar-08",id:"bonuses/seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n",source:"@site/pb071/bonuses/08.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-08",permalink:"/pb071/bonuses/seminar-08",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/08.md",tags:[],version:"current",lastUpdatedAt:1694109587,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-08",title:"8th seminar",description:"Manipulating with files only char-by-char and a magic tree.\n"},sidebar:"autogeneratedBar",previous:{title:"5th and 6th seminar",permalink:"/pb071/bonuses/seminar-05-06"},next:{title:"10th seminar",permalink:"/pb071/bonuses/seminar-10"}},s={},u=[{value:"Introduction",id:"introduction",level:2},{value:"Warning",id:"warning",level:2},{value:"Testing",id:"testing",level:2},{value:"Task no. 1: Counting (0.75 K\u20a1)",id:"task-no-1-counting-075-k",level:2},{value:"Requirements",id:"requirements",level:3},{value:"Bonus part (0.75 K\u20a1)",id:"bonus-part-075-k",level:3},{value:"Task no. 2: Weird trees (1 K\u20a1)",id:"task-no-2-weird-trees-1-k",level:2},{value:"Submitting",id:"submitting",level:2}],p={toc:u},m="wrapper";function c(e){let{components:t,...r}=e;return(0,a.kt)(m,(0,i.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"8th-seminar-bonus-assignment"},"8th seminar bonus assignment"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/08.tar.gz"},"Source")),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"In this bonus you can implement two tasks, one of them has a bonus part with generic\nsolution."),(0,a.kt)("p",null,"One is focused on counting ananas or in case of generic version any substring in\nthe file, but with a restriction on the function you use."),(0,a.kt)("p",null,"Other one has a more algorithmic spirit."),(0,a.kt)("p",null,"For this bonus you can get at maximum 2.5 K\u20a1."),(0,a.kt)("h2",{id:"warning"},"Warning"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"DO NOT COMMIT test data")," to your own git repository, since the tests include\nfiles that exceed 10MB by themselves. Even if they are on separate branch, they\ntake up the space."),(0,a.kt)("h2",{id:"testing"},"Testing"),(0,a.kt)("p",null,"For testing you are provided with python script (requires ",(0,a.kt)("inlineCode",{parentName:"p"},"click")," to be installed:\n",(0,a.kt)("inlineCode",{parentName:"p"},"pip3 install --user click"),") and ",(0,a.kt)("inlineCode",{parentName:"p"},"Makefile")," that provides following targets:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check-counting")," - runs the ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," tests"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check-counting-bonus")," - runs the ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," tests with bonus implemented"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"check")," - runs both ",(0,a.kt)("inlineCode",{parentName:"li"},"counting")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"counting-bonus")," tests"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"clean")," - removes output files from the test runs")),(0,a.kt)("h2",{id:"task-no-1-counting-075-k"},"Task no. 1: Counting (0.75 K\u20a1)"),(0,a.kt)("p",null,"Your first task is to make smallish program that counts occurences of specific\n(or given) word from file and writes the number to other file."),(0,a.kt)("p",null,"Usage of the program is:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"Usage: ./counting [string-to-be-counted]\n")),(0,a.kt)("p",null,"Arguments that are passed to the program represent:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"")," - path to the file where we count the words"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"")," - path to the file where we output the count"),(0,a.kt)("li",{parentName:"ul"},"(optional argument) ",(0,a.kt)("inlineCode",{parentName:"li"},"[string-to-be-counted]")," - in case you implement bonus,\notherwise we default to word ",(0,a.kt)("inlineCode",{parentName:"li"},"ananas")," ;)")),(0,a.kt)("p",null,"In skeleton you are given 3 empty, but documented, functions to implement."),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"count_anything")," - function accepts input file and substring to be counted in\nthe file, returns the count."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"count_ananas")," - same as ",(0,a.kt)("inlineCode",{parentName:"li"},"count_anything"),", but specialized for ananases, the\ndefault implementation from the skeleton expects you to implement ",(0,a.kt)("inlineCode",{parentName:"li"},"count_anything"),"\nand therefore it just calls the other function."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("inlineCode",{parentName:"li"},"write_number")," - function that writes the number to the file, why would you\nneed the function is explained later :)")),(0,a.kt)("h3",{id:"requirements"},"Requirements"),(0,a.kt)("p",null,"For manipulation with the files you are only allowed to use ",(0,a.kt)("inlineCode",{parentName:"p"},"fopen"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"fclose"),",\n",(0,a.kt)("inlineCode",{parentName:"p"},"fgetc")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"fputc"),". Functions like ",(0,a.kt)("inlineCode",{parentName:"p"},"fprintf")," (except for ",(0,a.kt)("inlineCode",{parentName:"p"},"stderr")," or logging) and\n",(0,a.kt)("inlineCode",{parentName:"p"},"fscanf")," are ",(0,a.kt)("strong",{parentName:"p"},"forbidden"),"."),(0,a.kt)("p",null,"In case you struggle and want to use one of those functions, the solution will be\npenalized by 50% of points."),(0,a.kt)("h3",{id:"bonus-part-075-k"},"Bonus part (0.75 K\u20a1)"),(0,a.kt)("p",null,"Bonus part of this assignment is to implement ",(0,a.kt)("inlineCode",{parentName:"p"},"count_anything")," rather than ",(0,a.kt)("inlineCode",{parentName:"p"},"count_ananas"),"."),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Smaller hint: This task does not need dynamic allocation :) You just need one\ngood helper function and the right idea ;)")),(0,a.kt)("h2",{id:"task-no-2-weird-trees-1-k"},"Task no. 2: Weird trees (1 K\u20a1)"),(0,a.kt)("p",null,"In this task we are crossing our paths with ",(0,a.kt)("em",{parentName:"p"},"algorithms and data structures"),".\nYour task is to write a program that constructs tree from the file that is given\nas an argument and pretty-prints it."),(0,a.kt)("p",null,"Input file consists of lines, that include ",(0,a.kt)("inlineCode",{parentName:"p"},"key")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"rank")," in form ",(0,a.kt)("inlineCode",{parentName:"p"},"key;rank"),"\nor ",(0,a.kt)("inlineCode",{parentName:"p"},"nil"),". Why would we have ",(0,a.kt)("inlineCode",{parentName:"p"},"nil")," in a file? The file represents pre-order iteration\nthrough the tree. Leaves never have rank different than 0, so you can safely assume\n2 non-existing ",(0,a.kt)("inlineCode",{parentName:"p"},"nil"),"s in the input after you read such node ;)"),(0,a.kt)("table",null,(0,a.kt)("tr",null,(0,a.kt)("th",null,"Example input file"),(0,a.kt)("th",null,"Tree it represents")),(0,a.kt)("tr",null,(0,a.kt)("td",null,(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"8;4\n5;3\n3;2\n2;1\n1;0\nnil\n4;0\n7;1\n6;0\nnil\n11;2\n10;1\n9;0\nnil\n12;0\n"))),(0,a.kt)("td",null,(0,a.kt)("p",null,(0,a.kt)("img",{alt:"tree",src:n(4860).Z,width:"633",height:"684"}))))),(0,a.kt)("p",null,"In this task you are only provided with different trees in the ",(0,a.kt)("inlineCode",{parentName:"p"},"test-trees")," directory.\nImplementation and format of the pretty-print is totally up to you. :)"),(0,a.kt)("p",null,"Example of mine for the tree above:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"8 (rank = 4)\n+-- 5 (rank = 3)\n| +-- 3 (rank = 2)\n| | +-- 2 (rank = 1)\n| | | +-- 1 (rank = 0)\n| | +-- 4 (rank = 0)\n| +-- 7 (rank = 1)\n| +-- 6 (rank = 0)\n+-- 11 (rank = 2)\n +-- 10 (rank = 1)\n | +-- 9 (rank = 0)\n +-- 12 (rank = 0)\n")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Can you find out what are those trees? :)")),(0,a.kt)("h2",{id:"submitting"},"Submitting"),(0,a.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Ideally submit the assignment through the merge request. Step-by-step tutorial is\npresent ",(0,a.kt)("a",{parentName:"p",href:"../mr"},"here"),". For setting assignee my xlogin is ",(0,a.kt)("inlineCode",{parentName:"p"},"xfocko"),"."),(0,a.kt)("p",null,"In case you do not want to experiment on GitLab, send me the source code via email,\nbut please prefix subject with: ",(0,a.kt)("inlineCode",{parentName:"p"},"[PB071/14][seminar-08]")),(0,a.kt)("p",null,"Deadline for the submission of the bonus is ",(0,a.kt)("strong",{parentName:"p"},"May 4th 24:00"),"."))}c.isMDXComponent=!0},4860:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/tree-c9e37f87f9095c00fad33ea034485ce6.png"}}]); \ No newline at end of file diff --git a/assets/js/337bc122.a2fd825d.js b/assets/js/337bc122.22826266.js similarity index 97% rename from assets/js/337bc122.a2fd825d.js rename to assets/js/337bc122.22826266.js index 16ed7a1..9d72365 100644 --- a/assets/js/337bc122.a2fd825d.js +++ b/assets/js/337bc122.22826266.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1731],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>b});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=l(r),d=o,b=s["".concat(p,".").concat(d)]||s[d]||f[d]||a;return r?n.createElement(b,i(i({ref:t},u),{},{components:r})):n.createElement(b,i({ref:t},u))}));function b(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[s]="string"==typeof e?e:o,i[1]=c;for(var l=2;l{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={id:"pb071-intro",title:"Introduction",slug:"/"},i=void 0,c={unversionedId:"pb071-intro",id:"pb071-intro",title:"Introduction",description:"",source:"@site/pb071/00-intro-pb071.md",sourceDirName:".",slug:"/",permalink:"/pb071/",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/00-intro-pb071.md",tags:[],version:"current",lastUpdatedAt:1694108971,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"pb071-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Bonuses",permalink:"/pb071/category/bonuses"}},p={},l=[],u={toc:l},s="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[1731],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>b});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=l(r),d=o,b=s["".concat(p,".").concat(d)]||s[d]||f[d]||a;return r?n.createElement(b,i(i({ref:t},u),{},{components:r})):n.createElement(b,i({ref:t},u))}));function b(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[s]="string"==typeof e?e:o,i[1]=c;for(var l=2;l{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={id:"pb071-intro",title:"Introduction",slug:"/"},i=void 0,c={unversionedId:"pb071-intro",id:"pb071-intro",title:"Introduction",description:"",source:"@site/pb071/00-intro-pb071.md",sourceDirName:".",slug:"/",permalink:"/pb071/",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/00-intro-pb071.md",tags:[],version:"current",lastUpdatedAt:1694109587,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"pb071-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Bonuses",permalink:"/pb071/category/bonuses"}},p={},l=[],u={toc:l},s="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4ee12fa2.74d68d7b.js b/assets/js/4ee12fa2.bd3f9667.js similarity index 97% rename from assets/js/4ee12fa2.74d68d7b.js rename to assets/js/4ee12fa2.bd3f9667.js index f0db623..89da5d6 100644 --- a/assets/js/4ee12fa2.74d68d7b.js +++ b/assets/js/4ee12fa2.bd3f9667.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7963],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=l(r),d=o,m=s["".concat(p,".").concat(d)]||s[d]||f[d]||i;return r?n.createElement(m,a(a({ref:t},u),{},{components:r})):n.createElement(m,a({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[s]="string"==typeof e?e:o,a[1]=c;for(var l=2;l{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>a,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const i={id:"pb161-intro",title:"Introduction",slug:"/"},a=void 0,c={unversionedId:"pb161-intro",id:"pb161-intro",title:"Introduction",description:"",source:"@site/pb161/00-intro-pb161.md",sourceDirName:".",slug:"/",permalink:"/pb161/",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb161/00-intro-pb161.md",tags:[],version:"current",lastUpdatedAt:1694108971,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"pb161-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Environment",permalink:"/pb161/environment"}},p={},l=[],u={toc:l},s="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7963],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function a(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var p=n.createContext({}),l=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},s="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,i=e.originalType,p=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),s=l(r),d=o,m=s["".concat(p,".").concat(d)]||s[d]||f[d]||i;return r?n.createElement(m,a(a({ref:t},u),{},{components:r})):n.createElement(m,a({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=r.length,a=new Array(i);a[0]=d;var c={};for(var p in t)hasOwnProperty.call(t,p)&&(c[p]=t[p]);c.originalType=e,c[s]="string"==typeof e?e:o,a[1]=c;for(var l=2;l{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>a,default:()=>f,frontMatter:()=>i,metadata:()=>c,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const i={id:"pb161-intro",title:"Introduction",slug:"/"},a=void 0,c={unversionedId:"pb161-intro",id:"pb161-intro",title:"Introduction",description:"",source:"@site/pb161/00-intro-pb161.md",sourceDirName:".",slug:"/",permalink:"/pb161/",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb161/00-intro-pb161.md",tags:[],version:"current",lastUpdatedAt:1694109587,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"pb161-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Environment",permalink:"/pb161/environment"}},p={},l=[],u={toc:l},s="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7cf94373.f790d5a8.js b/assets/js/7cf94373.f6d9052f.js similarity index 99% rename from assets/js/7cf94373.f790d5a8.js rename to assets/js/7cf94373.f6d9052f.js index 8d919bc..d7bb761 100644 --- a/assets/js/7cf94373.f790d5a8.js +++ b/assets/js/7cf94373.f6d9052f.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3095],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=p(n),d=r,k=m["".concat(l,".").concat(d)]||m[d]||c[d]||i;return n?a.createElement(k,o(o({ref:t},u),{},{components:n})):a.createElement(k,o({ref:t},u))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:r,o[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const i={id:"seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n"},o=void 0,s={unversionedId:"bonuses/seminar-10",id:"bonuses/seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n",source:"@site/pb071/bonuses/10.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-10",permalink:"/pb071/bonuses/seminar-10",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/10.md",tags:[],version:"current",lastUpdatedAt:1694108971,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n"},sidebar:"autogeneratedBar",previous:{title:"8th seminar",permalink:"/pb071/bonuses/seminar-08"},next:{title:"Practice Exams",permalink:"/pb071/category/practice-exams"}},l={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Project",id:"project",level:2},{value:"Summary of the gameplay",id:"summary-of-the-gameplay",level:3},{value:"Suggested workflow",id:"suggested-workflow",level:2},{value:"Tasks",id:"tasks",level:2},{value:"Dictionary",id:"dictionary",level:2},{value:"Submitting",id:"submitting",level:2}],u={toc:p},m="wrapper";function c(e){let{components:t,...i}=e;return(0,r.kt)(m,(0,a.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/10.tar.gz"},"Source")),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"For this bonus you are given almost finished project - The Hangman Game. Your\ntask is to try the game, in case you find any bugs point them out and cover as\nmuch of the game as possible with tests."),(0,r.kt)("p",null,"For this bonus you can get at maximum 2 K\u20a1."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Item"),(0,r.kt)("th",{parentName:"tr",align:null},"Bonus"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Fixing bugs from failing tests"),(0,r.kt)("td",{parentName:"tr",align:null},"0.25")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"word_guessed")),(0,r.kt)("td",{parentName:"tr",align:null},"0.50")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Hidden bug"),(0,r.kt)("td",{parentName:"tr",align:null},"0.50")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Extending tests, undetectable bugs or evil bug"),(0,r.kt)("td",{parentName:"tr",align:null},"0.37")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Refactor"),(0,r.kt)("td",{parentName:"tr",align:null},"0.38")))),(0,r.kt)("h2",{id:"project"},"Project"),(0,r.kt)("p",null,"Project consists of 2 source files - ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman.c")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"main.c"),"."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"main.c")," is quite short and concise, there is nothing for you to do."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"hangman.c")," contains implementation of the game. In case you feel lost, consult\nthe documentation in ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman.h")," that represents an interface that can be used\nfor implementing the game."),(0,r.kt)("p",null,"Apart from those sources this project is a bit more complicated. ",(0,r.kt)("em",{parentName:"p"},"Game loop")," is\nrealised via single encapsulated function that complicates the testing. Because\nof that, there are 2 kinds of tests:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"Unit tests")," - that are present in ",(0,r.kt)("inlineCode",{parentName:"p"},"test_hangman.c")," and can be run via:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"$ make check-unit\n")),(0,r.kt)("p",{parentName:"li"},"They cover majorly functions that can be tested easily via testing framework.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"Functional tests")," - same as in ",(0,r.kt)("inlineCode",{parentName:"p"},"seminar-08")," and are focused on testing the\nprogram as whole. Basic smoke test is already included in ",(0,r.kt)("inlineCode",{parentName:"p"},"usage")," test case."),(0,r.kt)("p",{parentName:"li"},"They can be run via:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"$ make check-functional\n")),(0,r.kt)("p",{parentName:"li"},"When testing ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman")," function (the game loop), it is suggested to create\nfunctional tests."),(0,r.kt)("p",{parentName:"li"},"When submitting the files for review, please leave out functional tests that\nwere given as a part of the assignment, so that it is easier to navigate, I\nwill drag the common files myself. :)"))),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"Whole test suite can be run via:"),(0,r.kt)("pre",{parentName:"blockquote"},(0,r.kt)("code",{parentName:"pre"},"$ make check\n"))),(0,r.kt)("h3",{id:"summary-of-the-gameplay"},"Summary of the gameplay"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Secret word gets chosen from the file that's path is given as an argument."),(0,r.kt)("li",{parentName:"ol"},"You get 8 guesses."),(0,r.kt)("li",{parentName:"ol"},"Invalid characters don't count."),(0,r.kt)("li",{parentName:"ol"},"Already guessed characters don't count, even if not included in the secret."),(0,r.kt)("li",{parentName:"ol"},"You can guess the whole word at once",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"If you get it right, you won, game ends."),(0,r.kt)("li",{parentName:"ul"},"If you don't get it right, you get to see the secret, game ends."))),(0,r.kt)("li",{parentName:"ol"},"In case of end of input, game finishes via force."),(0,r.kt)("li",{parentName:"ol"},"In case of invalid input, no guesses are subtracted, game carries on."),(0,r.kt)("li",{parentName:"ol"},"Letters and words are not case sensitive.")),(0,r.kt)("h2",{id:"suggested-workflow"},"Suggested workflow"),(0,r.kt)("p",null,"As we have talked about on the seminar, I suggest you to follow\n",(0,r.kt)("em",{parentName:"p"},"Test-Driven Development"),"\nin this case."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"TDD workflow",src:n(1530).Z,width:"2814",height:"1652"})),(0,r.kt)("p",null,"In our current scenario we are already in the stage of refactoring and fixing the\nbugs. Therefore try to follow this succession of steps:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Try to reproduce the bug."),(0,r.kt)("li",{parentName:"ol"},"Create a test that proves the presence of the bug."),(0,r.kt)("li",{parentName:"ol"},"Fix the bug.")),(0,r.kt)("p",null,"In case you are submitting the bonus via GitLab, it is helpful to commit tests\nbefore commiting the fixes, so that it is apparent that the bug is manifested.\nExample of ",(0,r.kt)("inlineCode",{parentName:"p"},"git log")," (notice that the first line represents latest commit):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"feat: Implement fizz_buzzer\ntest: Add tests for fizz_buzzer\nfix: Fix NULL-check in print_name\ntest: Add test for NULL in print_name\n")),(0,r.kt)("h2",{id:"tasks"},"Tasks"),(0,r.kt)("p",null,"As to your tasks, there are multiple things wrong in this project."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},'There are 2 "bugs" that cannot be detected via tests, i.e. they are not bugs\nthat affect functionality of the game.')),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"There is one evil bug in ",(0,r.kt)("inlineCode",{parentName:"p"},"get_word"),". It is not required to be fixed ;) Assign\nit the lowest priority.")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"There are some tests failing. Please try to figure it out, so you have green\ntests for the rest :)")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"We have gotten a bug report for ",(0,r.kt)("inlineCode",{parentName:"p"},"word_guessed"),", all we got is"),(0,r.kt)("blockquote",{parentName:"li"},(0,r.kt)("p",{parentName:"blockquote"},"doesn't work when there are too many ",(0,r.kt)("inlineCode",{parentName:"p"},"a"),"s")),(0,r.kt)("p",{parentName:"li"},"Please try to replicate the bug and create a tests, so we don't get any\nregression later on.")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"One hidden bug :) Closely non-specified, we cannot reproduce it and we were\ndrunk while playing the game, so we don't remember a thing. :/")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Try to cover as much code via the tests as possible. We are not going to look\nat the metrics, but DRY is violated a lot, so as a last task try to remove as\nmuch of the duplicit code as possible."),(0,r.kt)("p",{parentName:"li"},"Tests should help you a lot in case there are some regressions."))),(0,r.kt)("hr",null),(0,r.kt)("p",null,"In case you wonder why there are always 3 same words in the file with words, it\nis because of the ",(0,r.kt)("inlineCode",{parentName:"p"},"get_word")," bug. It is not a bug that can be easily fixed, so\nit is a not requirement at all and you can still get all points for the bonus ;)"),(0,r.kt)("h2",{id:"dictionary"},"Dictionary"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Functional_testing"},"Functional tests")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Smoke_testing_%28software%29"},"Smoke test")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"},"DRY"))),(0,r.kt)("h2",{id:"submitting"},"Submitting"),(0,r.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,r.kt)("hr",null),(0,r.kt)("p",null,"Ideally submit the assignment through the merge request. Step-by-step tutorial\nis present ",(0,r.kt)("a",{parentName:"p",href:"../mr"},"here"),". For setting assignee my xlogin is ",(0,r.kt)("inlineCode",{parentName:"p"},"xfocko"),"."),(0,r.kt)("p",null,"In case you do not want to experiment on GitLab, send me the source code via\nemail, but please prefix subject with: ",(0,r.kt)("inlineCode",{parentName:"p"},"[PB071/14][seminar-10]")),(0,r.kt)("p",null,"Deadline for the submission of the bonus is ",(0,r.kt)("strong",{parentName:"p"},"May 17 24:00"),"."))}c.isMDXComponent=!0},1530:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/tdd_lifecycle-327ad9ee0ed8318ed11e19a28e02b2cc.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3095],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=p(n),d=r,k=m["".concat(l,".").concat(d)]||m[d]||c[d]||i;return n?a.createElement(k,o(o({ref:t},u),{},{components:n})):a.createElement(k,o({ref:t},u))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:r,o[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var a=n(7462),r=(n(7294),n(3905));const i={id:"seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n"},o=void 0,s={unversionedId:"bonuses/seminar-10",id:"bonuses/seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n",source:"@site/pb071/bonuses/10.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-10",permalink:"/pb071/bonuses/seminar-10",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/10.md",tags:[],version:"current",lastUpdatedAt:1694109587,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-10",title:"10th seminar",description:"Finding bugs in a hangman.\n"},sidebar:"autogeneratedBar",previous:{title:"8th seminar",permalink:"/pb071/bonuses/seminar-08"},next:{title:"Practice Exams",permalink:"/pb071/category/practice-exams"}},l={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Project",id:"project",level:2},{value:"Summary of the gameplay",id:"summary-of-the-gameplay",level:3},{value:"Suggested workflow",id:"suggested-workflow",level:2},{value:"Tasks",id:"tasks",level:2},{value:"Dictionary",id:"dictionary",level:2},{value:"Submitting",id:"submitting",level:2}],u={toc:p},m="wrapper";function c(e){let{components:t,...i}=e;return(0,r.kt)(m,(0,a.Z)({},u,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/10.tar.gz"},"Source")),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"For this bonus you are given almost finished project - The Hangman Game. Your\ntask is to try the game, in case you find any bugs point them out and cover as\nmuch of the game as possible with tests."),(0,r.kt)("p",null,"For this bonus you can get at maximum 2 K\u20a1."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Item"),(0,r.kt)("th",{parentName:"tr",align:null},"Bonus"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Fixing bugs from failing tests"),(0,r.kt)("td",{parentName:"tr",align:null},"0.25")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"word_guessed")),(0,r.kt)("td",{parentName:"tr",align:null},"0.50")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Hidden bug"),(0,r.kt)("td",{parentName:"tr",align:null},"0.50")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Extending tests, undetectable bugs or evil bug"),(0,r.kt)("td",{parentName:"tr",align:null},"0.37")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"Refactor"),(0,r.kt)("td",{parentName:"tr",align:null},"0.38")))),(0,r.kt)("h2",{id:"project"},"Project"),(0,r.kt)("p",null,"Project consists of 2 source files - ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman.c")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"main.c"),"."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"main.c")," is quite short and concise, there is nothing for you to do."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"hangman.c")," contains implementation of the game. In case you feel lost, consult\nthe documentation in ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman.h")," that represents an interface that can be used\nfor implementing the game."),(0,r.kt)("p",null,"Apart from those sources this project is a bit more complicated. ",(0,r.kt)("em",{parentName:"p"},"Game loop")," is\nrealised via single encapsulated function that complicates the testing. Because\nof that, there are 2 kinds of tests:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"Unit tests")," - that are present in ",(0,r.kt)("inlineCode",{parentName:"p"},"test_hangman.c")," and can be run via:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"$ make check-unit\n")),(0,r.kt)("p",{parentName:"li"},"They cover majorly functions that can be tested easily via testing framework.")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("p",{parentName:"li"},(0,r.kt)("em",{parentName:"p"},"Functional tests")," - same as in ",(0,r.kt)("inlineCode",{parentName:"p"},"seminar-08")," and are focused on testing the\nprogram as whole. Basic smoke test is already included in ",(0,r.kt)("inlineCode",{parentName:"p"},"usage")," test case."),(0,r.kt)("p",{parentName:"li"},"They can be run via:"),(0,r.kt)("pre",{parentName:"li"},(0,r.kt)("code",{parentName:"pre"},"$ make check-functional\n")),(0,r.kt)("p",{parentName:"li"},"When testing ",(0,r.kt)("inlineCode",{parentName:"p"},"hangman")," function (the game loop), it is suggested to create\nfunctional tests."),(0,r.kt)("p",{parentName:"li"},"When submitting the files for review, please leave out functional tests that\nwere given as a part of the assignment, so that it is easier to navigate, I\nwill drag the common files myself. :)"))),(0,r.kt)("blockquote",null,(0,r.kt)("p",{parentName:"blockquote"},"Whole test suite can be run via:"),(0,r.kt)("pre",{parentName:"blockquote"},(0,r.kt)("code",{parentName:"pre"},"$ make check\n"))),(0,r.kt)("h3",{id:"summary-of-the-gameplay"},"Summary of the gameplay"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Secret word gets chosen from the file that's path is given as an argument."),(0,r.kt)("li",{parentName:"ol"},"You get 8 guesses."),(0,r.kt)("li",{parentName:"ol"},"Invalid characters don't count."),(0,r.kt)("li",{parentName:"ol"},"Already guessed characters don't count, even if not included in the secret."),(0,r.kt)("li",{parentName:"ol"},"You can guess the whole word at once",(0,r.kt)("ul",{parentName:"li"},(0,r.kt)("li",{parentName:"ul"},"If you get it right, you won, game ends."),(0,r.kt)("li",{parentName:"ul"},"If you don't get it right, you get to see the secret, game ends."))),(0,r.kt)("li",{parentName:"ol"},"In case of end of input, game finishes via force."),(0,r.kt)("li",{parentName:"ol"},"In case of invalid input, no guesses are subtracted, game carries on."),(0,r.kt)("li",{parentName:"ol"},"Letters and words are not case sensitive.")),(0,r.kt)("h2",{id:"suggested-workflow"},"Suggested workflow"),(0,r.kt)("p",null,"As we have talked about on the seminar, I suggest you to follow\n",(0,r.kt)("em",{parentName:"p"},"Test-Driven Development"),"\nin this case."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"TDD workflow",src:n(1530).Z,width:"2814",height:"1652"})),(0,r.kt)("p",null,"In our current scenario we are already in the stage of refactoring and fixing the\nbugs. Therefore try to follow this succession of steps:"),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"Try to reproduce the bug."),(0,r.kt)("li",{parentName:"ol"},"Create a test that proves the presence of the bug."),(0,r.kt)("li",{parentName:"ol"},"Fix the bug.")),(0,r.kt)("p",null,"In case you are submitting the bonus via GitLab, it is helpful to commit tests\nbefore commiting the fixes, so that it is apparent that the bug is manifested.\nExample of ",(0,r.kt)("inlineCode",{parentName:"p"},"git log")," (notice that the first line represents latest commit):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"feat: Implement fizz_buzzer\ntest: Add tests for fizz_buzzer\nfix: Fix NULL-check in print_name\ntest: Add test for NULL in print_name\n")),(0,r.kt)("h2",{id:"tasks"},"Tasks"),(0,r.kt)("p",null,"As to your tasks, there are multiple things wrong in this project."),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},'There are 2 "bugs" that cannot be detected via tests, i.e. they are not bugs\nthat affect functionality of the game.')),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"There is one evil bug in ",(0,r.kt)("inlineCode",{parentName:"p"},"get_word"),". It is not required to be fixed ;) Assign\nit the lowest priority.")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"There are some tests failing. Please try to figure it out, so you have green\ntests for the rest :)")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"We have gotten a bug report for ",(0,r.kt)("inlineCode",{parentName:"p"},"word_guessed"),", all we got is"),(0,r.kt)("blockquote",{parentName:"li"},(0,r.kt)("p",{parentName:"blockquote"},"doesn't work when there are too many ",(0,r.kt)("inlineCode",{parentName:"p"},"a"),"s")),(0,r.kt)("p",{parentName:"li"},"Please try to replicate the bug and create a tests, so we don't get any\nregression later on.")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"One hidden bug :) Closely non-specified, we cannot reproduce it and we were\ndrunk while playing the game, so we don't remember a thing. :/")),(0,r.kt)("li",{parentName:"ol"},(0,r.kt)("p",{parentName:"li"},"Try to cover as much code via the tests as possible. We are not going to look\nat the metrics, but DRY is violated a lot, so as a last task try to remove as\nmuch of the duplicit code as possible."),(0,r.kt)("p",{parentName:"li"},"Tests should help you a lot in case there are some regressions."))),(0,r.kt)("hr",null),(0,r.kt)("p",null,"In case you wonder why there are always 3 same words in the file with words, it\nis because of the ",(0,r.kt)("inlineCode",{parentName:"p"},"get_word")," bug. It is not a bug that can be easily fixed, so\nit is a not requirement at all and you can still get all points for the bonus ;)"),(0,r.kt)("h2",{id:"dictionary"},"Dictionary"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Functional_testing"},"Functional tests")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Smoke_testing_%28software%29"},"Smoke test")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"},"DRY"))),(0,r.kt)("h2",{id:"submitting"},"Submitting"),(0,r.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,r.kt)("hr",null),(0,r.kt)("p",null,"Ideally submit the assignment through the merge request. Step-by-step tutorial\nis present ",(0,r.kt)("a",{parentName:"p",href:"../mr"},"here"),". For setting assignee my xlogin is ",(0,r.kt)("inlineCode",{parentName:"p"},"xfocko"),"."),(0,r.kt)("p",null,"In case you do not want to experiment on GitLab, send me the source code via\nemail, but please prefix subject with: ",(0,r.kt)("inlineCode",{parentName:"p"},"[PB071/14][seminar-10]")),(0,r.kt)("p",null,"Deadline for the submission of the bonus is ",(0,r.kt)("strong",{parentName:"p"},"May 17 24:00"),"."))}c.isMDXComponent=!0},1530:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/tdd_lifecycle-327ad9ee0ed8318ed11e19a28e02b2cc.png"}}]); \ No newline at end of file diff --git a/assets/js/7d580cdb.71718a61.js b/assets/js/7d580cdb.bd936269.js similarity index 99% rename from assets/js/7d580cdb.71718a61.js rename to assets/js/7d580cdb.bd936269.js index 1a660e5..5bd03bc 100644 --- a/assets/js/7d580cdb.71718a61.js +++ b/assets/js/7d580cdb.bd936269.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[8442],{3905:(a,e,t)=>{t.d(e,{Zo:()=>o,kt:()=>h});var n=t(7294);function s(a,e,t){return e in a?Object.defineProperty(a,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):a[e]=t,a}function m(a,e){var t=Object.keys(a);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(a);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(a,e).enumerable}))),t.push.apply(t,n)}return t}function p(a){for(var e=1;e=0||(s[t]=a[t]);return s}(a,e);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(a);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(a,t)&&(s[t]=a[t])}return s}var l=n.createContext({}),i=function(a){var e=n.useContext(l),t=e;return a&&(t="function"==typeof a?a(e):p(p({},e),a)),t},o=function(a){var e=i(a.components);return n.createElement(l.Provider,{value:e},a.children)},N="mdxType",c={inlineCode:"code",wrapper:function(a){var e=a.children;return n.createElement(n.Fragment,{},e)}},k=n.forwardRef((function(a,e){var t=a.components,s=a.mdxType,m=a.originalType,l=a.parentName,o=r(a,["components","mdxType","originalType","parentName"]),N=i(t),k=s,h=N["".concat(l,".").concat(k)]||N[k]||c[k]||m;return t?n.createElement(h,p(p({ref:e},o),{},{components:t})):n.createElement(h,p({ref:e},o))}));function h(a,e){var t=arguments,s=e&&e.mdxType;if("string"==typeof a||s){var m=t.length,p=new Array(m);p[0]=k;var r={};for(var l in e)hasOwnProperty.call(e,l)&&(r[l]=e[l]);r.originalType=a,r[N]="string"==typeof a?a:s,p[1]=r;for(var i=2;i{t.r(e),t.d(e,{assets:()=>l,contentTitle:()=>p,default:()=>c,frontMatter:()=>m,metadata:()=>r,toc:()=>i});var n=t(7462),s=(t(7294),t(3905));const m={id:"pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",tags:["java","recursion","exponential","greedy","dynamic-programming","top-down-dp","bottom-up-dp"],last_updated:{date:new Date("2023-08-17T00:00:00.000Z")}},p=void 0,r={unversionedId:"recursion/pyramid-slide-down",id:"recursion/pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",source:"@site/ib002/04-recursion/2023-08-17-pyramid-slide-down.md",sourceDirName:"04-recursion",slug:"/recursion/pyramid-slide-down",permalink:"/ib002/recursion/pyramid-slide-down",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/04-recursion/2023-08-17-pyramid-slide-down.md",tags:[{label:"java",permalink:"/ib002/tags/java"},{label:"recursion",permalink:"/ib002/tags/recursion"},{label:"exponential",permalink:"/ib002/tags/exponential"},{label:"greedy",permalink:"/ib002/tags/greedy"},{label:"dynamic-programming",permalink:"/ib002/tags/dynamic-programming"},{label:"top-down-dp",permalink:"/ib002/tags/top-down-dp"},{label:"bottom-up-dp",permalink:"/ib002/tags/bottom-up-dp"}],version:"current",lastUpdatedAt:1694108971,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",tags:["java","recursion","exponential","greedy","dynamic-programming","top-down-dp","bottom-up-dp"],last_updated:{date:"2023-08-17T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Recursion and backtracking with Robot Karel",permalink:"/ib002/recursion/karel-1"},next:{title:"Red-Black Trees",permalink:"/ib002/category/red-black-trees"}},l={},i=[{value:"Problem",id:"problem",level:2},{value:"Solving the problem",id:"solving-the-problem",level:2},{value:"Na\xefve solution",id:"na\xefve-solution",level:2},{value:"Time complexity",id:"time-complexity",level:3},{value:"Greedy solution",id:"greedy-solution",level:2},{value:"Time complexity",id:"time-complexity-1",level:3},{value:"Running the tests",id:"running-the-tests",level:3},{value:"Top-down DP",id:"top-down-dp",level:2},{value:"Time complexity",id:"time-complexity-2",level:3},{value:"Memory complexity",id:"memory-complexity",level:3},{value:"Bottom-up DP",id:"bottom-up-dp",level:2},{value:"Time complexity",id:"time-complexity-3",level:3},{value:"Memory complexity",id:"memory-complexity-1",level:3},{value:"Summary",id:"summary",level:2}],o={toc:i},N="wrapper";function c(a){let{components:e,...t}=a;return(0,s.kt)(N,(0,n.Z)({},o,t,{components:e,mdxType:"MDXLayout"}),(0,s.kt)("p",null,"In this post we will try to solve one problem in different ways."),(0,s.kt)("h2",{id:"problem"},"Problem"),(0,s.kt)("p",null,"The problem we are going to solve is one of ",(0,s.kt)("em",{parentName:"p"},"CodeWars")," katas and is called\n",(0,s.kt)("a",{parentName:"p",href:"https://www.codewars.com/kata/551f23362ff852e2ab000037"},"Pyramid Slide Down"),"."),(0,s.kt)("p",null,"We are given a 2D array of integers and we are to find the ",(0,s.kt)("em",{parentName:"p"},"slide down"),".\n",(0,s.kt)("em",{parentName:"p"},"Slide down")," is a maximum sum of consecutive numbers from the top to the bottom."),(0,s.kt)("p",null,"Let's have a look at few examples. Consider the following pyramid:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 3\n 7 4\n 2 4 6\n8 5 9 3\n")),(0,s.kt)("p",null,"This pyramid has following slide down:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," *3\n *7 4\n 2 *4 6\n8 5 *9 3\n")),(0,s.kt)("p",null,"And its value is ",(0,s.kt)("inlineCode",{parentName:"p"},"23"),"."),(0,s.kt)("p",null,"We can also have a look at a ",(0,s.kt)("em",{parentName:"p"},"bigger")," example:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 75\n 95 64\n 17 47 82\n 18 35 87 10\n 20 4 82 47 65\n 19 1 23 3 34\n 88 2 77 73 7 63 67\n 99 65 4 28 6 16 70 92\n 41 41 26 56 83 40 80 70 33\n 41 48 72 33 47 32 37 16 94 29\n 53 71 44 65 25 43 91 52 97 51 14\n 70 11 33 28 77 73 17 78 39 68 17 57\n 91 71 52 38 17 14 91 43 58 50 27 29 48\n 63 66 4 68 89 53 67 30 73 16 69 87 40 31\n 4 62 98 27 23 9 70 98 73 93 38 53 60 4 23\n")),(0,s.kt)("p",null,"Slide down in this case is equal to ",(0,s.kt)("inlineCode",{parentName:"p"},"1074"),"."),(0,s.kt)("h2",{id:"solving-the-problem"},"Solving the problem"),(0,s.kt)("admonition",{type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"I will describe the following ways you can approach this problem and implement\nthem in ",(0,s.kt)("em",{parentName:"p"},"Java"),(0,s.kt)("sup",{parentName:"p",id:"fnref-1"},(0,s.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),".")),(0,s.kt)("p",null,"For all of the following solutions I will be using basic ",(0,s.kt)("inlineCode",{parentName:"p"},"main")," function that\nwill output ",(0,s.kt)("inlineCode",{parentName:"p"},"true"),"/",(0,s.kt)("inlineCode",{parentName:"p"},"false")," based on the expected output of our algorithm. Any\nother differences will lie only in the solutions of the problem. You can see the\n",(0,s.kt)("inlineCode",{parentName:"p"},"main")," here:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},'public static void main(String[] args) {\n System.out.print("Test #1: ");\n System.out.println(longestSlideDown(new int[][] {\n { 3 },\n { 7, 4 },\n { 2, 4, 6 },\n { 8, 5, 9, 3 }\n }) == 23 ? "passed" : "failed");\n\n System.out.print("Test #2: ");\n System.out.println(longestSlideDown(new int[][] {\n { 75 },\n { 95, 64 },\n { 17, 47, 82 },\n { 18, 35, 87, 10 },\n { 20, 4, 82, 47, 65 },\n { 19, 1, 23, 75, 3, 34 },\n { 88, 2, 77, 73, 7, 63, 67 },\n { 99, 65, 4, 28, 6, 16, 70, 92 },\n { 41, 41, 26, 56, 83, 40, 80, 70, 33 },\n { 41, 48, 72, 33, 47, 32, 37, 16, 94, 29 },\n { 53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14 },\n { 70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57 },\n { 91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48 },\n { 63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31 },\n { 4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23 },\n }) == 1074 ? "passed" : "failed");\n}\n')),(0,s.kt)("h2",{id:"na\xefve-solution"},"Na\xefve solution"),(0,s.kt)("p",null,"Our na\xefve solution consists of trying out all the possible slides and finding\nthe one with maximum sum."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: We have gotten out of bounds, there's no reasonable value to\n // return, so we just return the \u2039MIN_VALUE\u203a to ensure that it cannot\n // be maximum.\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: Bottom of the pyramid, we just return the value, there's\n // nowhere to slide anymore.\n return pyramid[row][col];\n }\n\n // Otherwise we account for the current position and return maximum of the\n // available \u201cslides\u201d.\n return pyramid[row][col] + Math.max(\n longestSlideDown(pyramid, row + 1, col),\n longestSlideDown(pyramid, row + 1, col + 1));\n}\n\npublic static int longestSlideDown(int[][] pyramid) {\n // We start the slide in the top cell of the pyramid.\n return longestSlideDown(pyramid, 0, 0);\n}\n")),(0,s.kt)("p",null,"As you can see, we have 2 overloads:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"int longestSlideDown(int[][] pyramid);\nint longestSlideDown(int[][] pyramid, int row, int col);\n")),(0,s.kt)("p",null,"First one is used as a ",(0,s.kt)("em",{parentName:"p"},"public interface")," to the solution, you just pass in the\npyramid itself. Second one is the recursive \u201calgorithm\u201d that finds the slide\ndown."),(0,s.kt)("p",null,"It is a relatively simple solution\u2026 There's nothing to do at the bottom of the\npyramid, so we just return the value in the ",(0,s.kt)("em",{parentName:"p"},"cell"),". Otherwise we add it and try\nto slide down the available cells below the current row."),(0,s.kt)("h3",{id:"time-complexity"},"Time complexity"),(0,s.kt)("p",null,"If you get the source code and run it yourself, it runs rather fine\u2026 I hope you\nare wondering about the time complexity of the proposed solution and, since it\nreally is a na\xefve solution, the time complexity is pretty bad. Let's find the\nworst case scenario."),(0,s.kt)("p",null,"Let's start with the first overload:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid) {\n return longestSlideDown(pyramid, 0, 0);\n}\n")),(0,s.kt)("p",null,"There's not much to do here, so we can safely say that the time complexity of\nthis function is bounded by ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"))))),", where ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T")))))," is our second overload. This\ndoesn't tell us anything, so let's move on to the second overload where we are\ngoing to define the ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))," function."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: We have gotten out of bounds, there's no reasonable value to\n // return, so we just return the \u2039MIN_VALUE\u203a to ensure that it cannot\n // be maximum.\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: Bottom of the pyramid, we just return the value, there's\n // nowhere to slide anymore.\n return pyramid[row][col];\n }\n\n // Otherwise we account for the current position and return maximum of the\n // available \u201cslides\u201d.\n return pyramid[row][col] + Math.max(\n longestSlideDown(pyramid, row + 1, col),\n longestSlideDown(pyramid, row + 1, col + 1));\n}\n")),(0,s.kt)("p",null,"Fun fact is that the whole \u201calgorithm\u201d consists of just 2 ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statements\nand nothing else. Let's dissect them!"),(0,s.kt)("p",null,"First ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statement is the base case, so it has a constant time complexity."),(0,s.kt)("p",null,"Second one a bit tricky. We add two numbers together, which we'll consider as\nconstant, but for the right part of the expression we take maximum from the left\nand right paths. OK\u2026 So what happens? We evaluate the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown")," while\nchoosing the under and right both. They are separate computations though, so we\nare branching from each call of ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown"),", unless it's a base case."),(0,s.kt)("p",null,"What does that mean for us then? We basically get"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"{"),(0,s.kt)("mtable",{parentName:"mrow",rowspacing:"0.36em",columnalign:"left left",columnspacing:"1em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mn",{parentName:"mstyle"},"1"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mtext",{parentName:"mrow"},",\xa0if\xa0"),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mn",{parentName:"mrow"},"1"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"1"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mtext",{parentName:"mstyle"},",\xa0otherwise"))))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(y) = \\begin{cases} 1 & \\text{, if } y = rows \\\\ 1 + 2 \\cdot T(y + 1) & \\text{, otherwise} \\end{cases}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},(0,s.kt)("span",{parentName:"span",className:"delimsizing size4"},"{")),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.69em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.69em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"1"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.25em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"1"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"1"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.19em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"arraycolsep",style:{width:"1em"}}),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.69em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.69em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord text"},(0,s.kt)("span",{parentName:"span",className:"mord"},",\xa0if\xa0")),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.25em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord text"},(0,s.kt)("span",{parentName:"span",className:"mord"},",\xa0otherwise"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.19em"}},(0,s.kt)("span",{parentName:"span"}))))))),(0,s.kt)("span",{parentName:"span",className:"mclose nulldelimiter"}))))))),(0,s.kt)("p",null,"That looks rather easy to compute, isn't it? If you sum it up, you'll get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mo",{parentName:"mrow"},"\u2208"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("msup",{parentName:"mrow"},(0,s.kt)("mn",{parentName:"msup"},"2"),(0,s.kt)("mrow",{parentName:"msup"},(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"))),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(rows) \\in \\mathcal{O}(2^{rows})")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"\u2208"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.7144em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.113em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"s"))))))))),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"If you wonder why, I'll try to describe it intuitively:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"In each call to ",(0,s.kt)("inlineCode",{parentName:"li"},"longestSlideDown")," we do some work in constant time,\nregardless of being in the base case. Those are the ",(0,s.kt)("inlineCode",{parentName:"li"},"1"),"s in both cases."),(0,s.kt)("li",{parentName:"ol"},"If we are not in the base case, we move one row down ",(0,s.kt)("strong",{parentName:"li"},"twice"),". That's how we\nobtained ",(0,s.kt)("inlineCode",{parentName:"li"},"2 *")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"y + 1")," in the ",(0,s.kt)("em",{parentName:"li"},"otherwise")," case."),(0,s.kt)("li",{parentName:"ol"},"We move row-by-row, so we move down ",(0,s.kt)("inlineCode",{parentName:"li"},"y"),"-times and each call splits to two\nsubtrees."),(0,s.kt)("li",{parentName:"ol"},"Overall, if we were to represent the calls as a tree, we would get a full\nbinary tree of height ",(0,s.kt)("inlineCode",{parentName:"li"},"y"),", in each node we do some work in constant time,\ntherefore we can just sum the ones.")),(0,s.kt)("admonition",{type:"warning"},(0,s.kt)("p",{parentName:"admonition"},"It would've been more complicated to get an exact result. In the equation above\nwe are assuming that the width of the pyramid is bound by the height.")),(0,s.kt)("p",null,"Hopefully we can agree that this is not the best we can do. \ud83d\ude09"),(0,s.kt)("h2",{id:"greedy-solution"},"Greedy solution"),(0,s.kt)("p",null,"We will try to optimize it a bit. Let's start with a relatively simple ",(0,s.kt)("em",{parentName:"p"},"greedy"),"\napproach."),(0,s.kt)("admonition",{title:"Greedy algorithms",type:"info"},(0,s.kt)("p",{parentName:"admonition"},(0,s.kt)("em",{parentName:"p"},"Greedy algorithms")," can be described as algorithms that decide the action on the\noptimal option at the moment.")),(0,s.kt)("p",null,"We can try to adjust the na\xefve solution. The most problematic part are the\nrecursive calls. Let's apply the greedy approach there:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row == pyramid.length - 1) {\n // BASE: We're at the bottom\n return pyramid[row][col];\n }\n\n if (col + 1 >= pyramid[row + 1].length\n || pyramid[row + 1][col] > pyramid[row + 1][col + 1]) {\n // If we cannot go right or it's not feasible, we continue to the left.\n return pyramid[row][col] + longestSlideDown(pyramid, row + 1, col);\n }\n\n // Otherwise we just move to the right.\n return pyramid[row][col] + longestSlideDown(pyramid, row + 1, col + 1);\n}\n")),(0,s.kt)("p",null,"OK, if we cannot go right ",(0,s.kt)("strong",{parentName:"p"},"or")," the right path adds smaller value to the sum,\nwe simply go left."),(0,s.kt)("h3",{id:"time-complexity-1"},"Time complexity"),(0,s.kt)("p",null,"We have switched from ",(0,s.kt)("em",{parentName:"p"},"adding the maximum")," to ",(0,s.kt)("em",{parentName:"p"},"following the \u201cbigger\u201d path"),", so\nwe improved the time complexity tremendously. We just go down the pyramid all\nthe way to the bottom. Therefore we are getting:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"We have managed to convert our exponential solution into a linear one."),(0,s.kt)("h3",{id:"running-the-tests"},"Running the tests"),(0,s.kt)("p",null,"However, if we run the tests, we notice that the second test failed:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},"Test #1: passed\nTest #2: failed\n")),(0,s.kt)("p",null,"What's going on? Well, we have improved the time complexity, but greedy\nalgorithms are not the ideal solution to ",(0,s.kt)("strong",{parentName:"p"},"all")," problems. In this case there\nmay be a solution that is bigger than the one found using the greedy algorithm."),(0,s.kt)("p",null,"Imagine the following pyramid:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 1\n 2 3\n 5 6 7\n 8 9 10 11\n99 13 14 15 16\n")),(0,s.kt)("p",null,"We start at the top:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"1"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"2")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"3"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"3")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"3"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"6")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"7"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"7")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"7"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"10")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"11"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"11")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"11"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"15")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"16"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"16")," looks better, so\nwe choose it.")),(0,s.kt)("p",null,"Our final sum is: ",(0,s.kt)("inlineCode",{parentName:"p"},"1 + 3 + 7 + 11 + 16 = 38"),", but in the bottom left cell we\nhave a ",(0,s.kt)("inlineCode",{parentName:"p"},"99")," that is bigger than our whole sum."),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"Dijkstra's algorithm is a greedy algorithm too, try to think why it is correct.")),(0,s.kt)("h2",{id:"top-down-dp"},"Top-down DP"),(0,s.kt)("p",null,(0,s.kt)("em",{parentName:"p"},"Top-down dynamic programming")," is probably the most common approach, since (at\nleast looks like) is the easiest to implement. The whole point is avoiding the\nunnecessary computations that we have already done."),(0,s.kt)("p",null,"In our case, we can use our na\xefve solution and put a ",(0,s.kt)("em",{parentName:"p"},"cache")," on top of it that\nwill make sure, we don't do unnecessary calculations."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"// This \u201cstructure\u201d is required, since I have decided to use \u2039TreeMap\u203a which\n// requires the ordering on the keys. It represents one position in the pyramid.\nrecord Position(int row, int col) implements Comparable {\n public int compareTo(Position r) {\n if (row != r.row) {\n return Integer.valueOf(row).compareTo(r.row);\n }\n\n if (col != r.col) {\n return Integer.valueOf(col).compareTo(r.col);\n }\n\n return 0;\n }\n}\n\npublic static int longestSlideDown(\n int[][] pyramid,\n TreeMap cache,\n Position position) {\n int row = position.row;\n int col = position.col;\n\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: out of bounds\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: bottom of the pyramid\n return pyramid[position.row][position.col];\n }\n\n if (!cache.containsKey(position)) {\n // We haven't computed the position yet, so we run the same \u201cformula\u201d as\n // in the na\xefve version \xbband\xab we put calculated slide into the cache.\n // Next time we want the slide down from given position, it will be just\n // retrieved from the cache.\n int slideDown = Math.max(\n longestSlideDown(pyramid, cache, new Position(row + 1, col)),\n longestSlideDown(pyramid, cache, new Position(row + 1, col + 1)));\n cache.put(position, pyramid[row][col] + slideDown);\n }\n\n return cache.get(position);\n}\n\npublic static int longestSlideDown(int[][] pyramid) {\n // At the beginning we need to create a cache and share it across the calls.\n TreeMap cache = new TreeMap<>();\n return longestSlideDown(pyramid, cache, new Position(0, 0));\n}\n")),(0,s.kt)("p",null,"You have probably noticed that ",(0,s.kt)("inlineCode",{parentName:"p"},"record Position")," have appeared. Since we are\ncaching the already computed values, we need a \u201creasonable\u201d key. In this case we\nshare the cache only for one ",(0,s.kt)("em",{parentName:"p"},"run")," (i.e. pyramid) of the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown"),", so\nwe can cache just with the indices within the pyramid, i.e. the ",(0,s.kt)("inlineCode",{parentName:"p"},"Position"),"."),(0,s.kt)("admonition",{title:"Record",type:"tip"},(0,s.kt)("p",{parentName:"admonition"},(0,s.kt)("em",{parentName:"p"},"Record")," is relatively new addition to the Java language. It is basically an\nimmutable structure with implicitly defined ",(0,s.kt)("inlineCode",{parentName:"p"},".equals()"),", ",(0,s.kt)("inlineCode",{parentName:"p"},".hashCode()"),",\n",(0,s.kt)("inlineCode",{parentName:"p"},".toString()")," and getters for the attributes.")),(0,s.kt)("p",null,"Because of the choice of ",(0,s.kt)("inlineCode",{parentName:"p"},"TreeMap"),", we had to additionally define the ordering\non it."),(0,s.kt)("p",null,"In the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown")," you can notice that the computation which used to be\nat the end of the na\xefve version above, is now wrapped in an ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," statement that\nchecks for the presence of the position in the cache and computes the slide down\njust when it's needed."),(0,s.kt)("h3",{id:"time-complexity-2"},"Time complexity"),(0,s.kt)("p",null,"If you think that evaluating time complexity for this approach is a bit more\ntricky, you are right. Keeping the cache in mind, it is not the easiest thing\nto do. However there are some observations that might help us figure this out:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"Slide down from each position is calculated only once."),(0,s.kt)("li",{parentName:"ol"},"Once calculated, we use the result from the cache.")),(0,s.kt)("p",null,"Knowing this, we still cannot, at least easily, describe the time complexity of\nfinding the best slide down from a specific position, ",(0,s.kt)("strong",{parentName:"p"},"but")," we can bound it\nfrom above for the ",(0,s.kt)("strong",{parentName:"p"},"whole")," run from the top. Now the question is how we can do\nthat!"),(0,s.kt)("p",null,"Overall we are doing the same things for almost",(0,s.kt)("sup",{parentName:"p",id:"fnref-2"},(0,s.kt)("a",{parentName:"sup",href:"#fn-2",className:"footnote-ref"},"2"))," all of the positions within\nthe pyramid:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},"We calculate and store it (using the partial results stored in cache). This\nis done only once."),(0,s.kt)("p",{parentName:"li"},"For each calculation we take 2 values from the cache and insert one value.\nBecause we have chosen ",(0,s.kt)("inlineCode",{parentName:"p"},"TreeMap"),", these 3 operations have logarithmic time\ncomplexity and therefore this step is equivalent to ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mn",{parentName:"mrow"},"3"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"3 \\cdot \\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"3"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),"."),(0,s.kt)("p",{parentName:"li"},"However for the sake of simplicity, we are going to account only for the\ninsertion, the reason is rather simple, if we include the 2 retrievals here,\nit will be interleaved with the next step, therefore it is easier to keep the\nretrievals in the following point."),(0,s.kt)("admonition",{parentName:"li",type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"You might have noticed it's still not that easy, cause we're not having full\ncache right from the beginning, but the sum of those logarithms cannot be\nexpressed in a nice way, so taking the upper bound, i.e. expecting the cache\nto be full at all times, is the best option for nice and readable complexity\nof the whole approach.")),(0,s.kt)("p",{parentName:"li"},"Our final upper bound of this work is therefore ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),".")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},"We retrieve it from the cache. Same as in first point, but only twice, so we\nget ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2 \\cdot \\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),". "),(0,s.kt)("admonition",{parentName:"li",type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"It's done twice because of the ",(0,s.kt)("inlineCode",{parentName:"p"},".containsKey()")," in the ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," condition.")))),(0,s.kt)("p",null,"Okay, we have evaluated work done for each of the cells in the pyramid and now\nwe need to put it together."),(0,s.kt)("p",null,"Let's split the time complexity of our solution into two operands:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(r + s)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"r")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"r")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))))," will represent the ",(0,s.kt)("em",{parentName:"p"},"actual")," calculation of the cells and ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"s")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"s")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))))," will represent\nthe additional retrievals on top of the calculation."),(0,s.kt)("p",null,"We calculate the values only ",(0,s.kt)("strong",{parentName:"p"},"once"),", therefore we can safely agree on:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"r"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} r &= n \\cdot \\log{n} \\\\ \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1.5em",verticalAlign:"-0.5em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.16em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.5em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.16em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.5em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("p",null,"What about the ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"s")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"s")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))))," though? Key observation here is the fact that we have 2\nlookups on the tree in each of them ",(0,s.kt)("strong",{parentName:"p"},"and")," we do it twice, cause each cell has\nat most 2 parents:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"("),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",fence:"true"},")")))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"4"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} s &= n \\cdot 2 \\cdot \\left( 2 \\cdot \\log{n} \\right) \\\\ s &= 4 \\cdot n \\cdot \\log{n} \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose delimcenter",style:{top:"0em"}},")")))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"4"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"You might've noticed that lookups actually take more time than the construction\nof the results. This is not entirely true, since we have included the\n",(0,s.kt)("inlineCode",{parentName:"p"},".containsKey()")," and ",(0,s.kt)("inlineCode",{parentName:"p"},".get()")," from the ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statement in the second part."),(0,s.kt)("p",{parentName:"admonition"},"If we were to represent this more precisely, we could've gone with:"),(0,s.kt)("div",{parentName:"admonition",className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"r"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"3"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} r &= 3 \\cdot n \\cdot \\log{n} \\\\ s &= 2 \\cdot n \\cdot \\log{n} \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"3"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("p",{parentName:"admonition"},"On the other hand we are summing both numbers together, therefore in the end it\ndoesn't really matter."),(0,s.kt)("p",{parentName:"admonition"},"(",(0,s.kt)("em",{parentName:"p"},"Feel free to compare the sums of both \u201csplits\u201d."),")")),(0,s.kt)("p",null,"And so our final time complexity for the whole ",(0,s.kt)("em",{parentName:"p"},"top-down dynamic programming"),"\napproach is:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"4"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mn",{parentName:"mrow"},"5"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(r + s) \\\\ \\mathcal{O}(n \\cdot \\log{n} + 4 \\cdot n \\cdot \\log{n}) \\\\ \\mathcal{O}(5 \\cdot n \\cdot \\log{n}) \\\\ \\mathcal{O}(n \\cdot \\log{n})")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"4"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4445em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},"5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4445em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"As you can see, this is worse than our ",(0,s.kt)("em",{parentName:"p"},"greedy")," solution that was incorrect, but\nit's better than the ",(0,s.kt)("em",{parentName:"p"},"na\xefve")," one."),(0,s.kt)("h3",{id:"memory-complexity"},"Memory complexity"),(0,s.kt)("p",null,"With this approach we need to talk about the memory complexity too, because we\nhave introduced cache. If you think that the memory complexity is linear to the\ninput, you are right. We start at the top and try to find each and every slide\ndown. At the end we get the final result for ",(0,s.kt)("inlineCode",{parentName:"p"},"new Position(0, 0)"),", so we need to\ncompute everything below."),(0,s.kt)("p",null,"That's how we obtain:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," represents the total amount of cells in the pyramid, i.e."),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("munderover",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"munderover"},"\u2211"),(0,s.kt)("mrow",{parentName:"munderover"},(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"0")),(0,s.kt)("mrow",{parentName:"munderover"},(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"p"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"y"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"r"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"a"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"m"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"."),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"l"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"g"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"h")),(0,s.kt)("mo",{parentName:"mrow"},"\u2212"),(0,s.kt)("mn",{parentName:"mrow"},"1"))),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"p"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"y"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"r"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"a"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"m"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d")),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"["),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"]")),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"."),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"l"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"g"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"h"))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\sum_{y=0}^{\\mathtt{pyramid.length} - 1} \\mathtt{pyramid}\\left[y\\right]\\mathtt{.length}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3.2709em",verticalAlign:"-1.4032em"}}),(0,s.kt)("span",{parentName:"span",className:"mop op-limits"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.8677em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-1.8829em",marginLeft:"0em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mrel mtight"},"="),(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,s.kt)("span",{parentName:"span",style:{top:"-3.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span"},(0,s.kt)("span",{parentName:"span",className:"mop op-symbol large-op"},"\u2211"))),(0,s.kt)("span",{parentName:"span",style:{top:"-4.3666em",marginLeft:"0em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt mtight"},"pyramid.length")),(0,s.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.4032em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt"},"pyramid")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},"["),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mclose delimcenter",style:{top:"0em"}},"]")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt"},".length"))))))),(0,s.kt)("admonition",{type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"If you're wondering whether it's correct because of the second ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," in our\nfunction, your guess is right. However we are expressing the complexity in the\nBachmann-Landau notation, so we care about the ",(0,s.kt)("strong",{parentName:"p"},"upper bound"),", not the exact\nnumber.")),(0,s.kt)("admonition",{title:"Can this be optimized?",type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"Yes, it can! Try to think about a way, how can you minimize the memory\ncomplexity of this approach. I'll give you a hint:"),(0,s.kt)("div",{parentName:"admonition",className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"))))))),(0,s.kt)("h2",{id:"bottom-up-dp"},"Bottom-up DP"),(0,s.kt)("p",null,"If you try to think in depth about the top-down DP solution, you might notice\nthat the ",(0,s.kt)("em",{parentName:"p"},"core")," of it stands on caching the calculations that have been already\ndone on the lower \u201clevels\u201d of the pyramid. Our bottom-up implementation will be\nusing this fact!"),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"As I have said in the ",(0,s.kt)("em",{parentName:"p"},"top-down DP")," section, it is the easiest way to implement\nDP (unless the cached function has complicated parameters, in that case it might\nget messy)."),(0,s.kt)("p",{parentName:"admonition"},"Bottom-up dynamic programming can be more effective, but may be more complicated\nto implement right from the beginning.")),(0,s.kt)("p",null,"Let's see how we can implement it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid) {\n // In the beginning we declare new array. At this point it is easier to just\n // work with the one dimension, i.e. just allocating the space for the rows.\n int[][] slideDowns = new int[pyramid.length][];\n\n // Bottom row gets just copied, there's nothing else to do\u2026 It's the base\n // case.\n slideDowns[pyramid.length - 1] = Arrays.copyOf(pyramid[pyramid.length - 1],\n pyramid[pyramid.length - 1].length);\n\n // Then we need to propagate the found slide downs for each of the levels\n // above.\n for (int y = pyramid.length - 2; y >= 0; --y) {\n // We start by copying the values lying in the row we're processing.\n // They get included in the final sum and we need to allocate the space\n // for the precalculated slide downs anyways.\n int[] row = Arrays.copyOf(pyramid[y], pyramid[y].length);\n\n // At this we just need to \u201cfetch\u201d the partial results from \u201cneighbours\u201d\n for (int x = 0; x < row.length; ++x) {\n // We look under our position, since we expect the rows to get\n // shorter, we can safely assume such position exists.\n int under = slideDowns[y + 1][x];\n\n // Then we have a look to the right, such position doesn't have to\n // exist, e.g. on the right edge, so we validate the index, and if\n // it doesn't exist, we just assign minimum of the \u2039int\u203a which makes\n // sure that it doesn't get picked in the \u2039Math.max()\u203a call.\n int toRight = x + 1 < slideDowns[y + 1].length\n ? slideDowns[y + 1][x + 1]\n : Integer.MIN_VALUE;\n\n // Finally we add the best choice at this point.\n row[x] += Math.max(under, toRight);\n }\n\n // And save the row we've just calculated partial results for to the\n // \u201ctable\u201d.\n slideDowns[y] = row;\n }\n\n // At the end we can find our seeked slide down at the top cell.\n return slideDowns[0][0];\n}\n")),(0,s.kt)("p",null,"I've tried to explain the code as much as possible within the comments, since it\nmight be more beneficial to see right next to the \u201coffending\u201d lines."),(0,s.kt)("p",null,"As you can see, in this approach we go from the other side",(0,s.kt)("sup",{parentName:"p",id:"fnref-3"},(0,s.kt)("a",{parentName:"sup",href:"#fn-3",className:"footnote-ref"},"3")),", the bottom of\nthe pyramid and propagate the partial results up."),(0,s.kt)("admonition",{type:"info"},(0,s.kt)("mdxAdmonitionTitle",{parentName:"admonition"},"How is this different from the ",(0,s.kt)("em",{parentName:"mdxAdmonitionTitle"},"greedy")," solution???"),(0,s.kt)("p",{parentName:"admonition"},"If you try to compare them, you might find a very noticable difference. The\ngreedy approach is going from the top to the bottom without ",(0,s.kt)("strong",{parentName:"p"},"any")," knowledge of\nwhat's going on below. On the other hand, bottom-up DP is going from the bottom\n(",(0,s.kt)("em",{parentName:"p"},"DUH\u2026"),") and ",(0,s.kt)("strong",{parentName:"p"},"propagates")," the partial results to the top. The propagation is\nwhat makes sure that at the top I don't choose the best ",(0,s.kt)("strong",{parentName:"p"},"local")," choice, but\nthe best ",(0,s.kt)("strong",{parentName:"p"},"overall")," result I can achieve.")),(0,s.kt)("h3",{id:"time-complexity-3"},"Time complexity"),(0,s.kt)("p",null,"Time complexity of this solution is rather simple. We allocate an array for the\nrows and then for each row, we copy it and adjust the partial results. Doing\nthis we get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows + 2n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"Of course, this is an upper bound, since we iterate through the bottom row only\nonce."),(0,s.kt)("h3",{id:"memory-complexity-1"},"Memory complexity"),(0,s.kt)("p",null,"We're allocating an array for the pyramid ",(0,s.kt)("strong",{parentName:"p"},"again")," for our partial results, so\nwe get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"If we were writing this in C++ or Rust, we could've avoided that, but not\nreally."),(0,s.kt)("p",{parentName:"admonition"},"C++ would allow us to ",(0,s.kt)("strong",{parentName:"p"},"copy")," the pyramid rightaway into the parameter, so we\nwould be able to directly change it. However it's still a copy, even though we\ndon't need to allocate anything ourselves. It's just implicitly done for us."),(0,s.kt)("p",{parentName:"admonition"},"Rust is more funny in this case. If the pyramids weren't used after the call of\n",(0,s.kt)("inlineCode",{parentName:"p"},"longest_slide_down"),", it would simply ",(0,s.kt)("strong",{parentName:"p"},"move")," them into the functions. If they\nwere used afterwards, the compiler would force you to either borrow it, or\n",(0,s.kt)("em",{parentName:"p"},"clone-and-move")," for the function."),(0,s.kt)("hr",{parentName:"admonition"}),(0,s.kt)("p",{parentName:"admonition"},"Since we're doing it in Java, we get a reference to the ",(0,s.kt)("em",{parentName:"p"},"original")," array and we\ncan't do whatever we want with it.")),(0,s.kt)("h2",{id:"summary"},"Summary"),(0,s.kt)("p",null,"And we've finally reached the end. We have seen 4 different \u201csolutions\u201d",(0,s.kt)("sup",{parentName:"p",id:"fnref-4"},(0,s.kt)("a",{parentName:"sup",href:"#fn-4",className:"footnote-ref"},"4"))," of\nthe same problem using different approaches. Different approaches follow the\norder in which you might come up with them, each approach influences its\nsuccessor and represents the way we can enhance the existing implementation."),(0,s.kt)("hr",null),(0,s.kt)("admonition",{title:"source",type:"info"},(0,s.kt)("p",{parentName:"admonition"},"You can find source code referenced in the text\n",(0,s.kt)("a",{parentName:"p",href:"pathname:///files/ib002/recursion/pyramid-slide-down.tar.gz"},"here"),".")),(0,s.kt)("div",{className:"footnotes"},(0,s.kt)("hr",{parentName:"div"}),(0,s.kt)("ol",{parentName:"div"},(0,s.kt)("li",{parentName:"ol",id:"fn-1"},"cause why not, right!?",(0,s.kt)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-2"},"except the bottom row",(0,s.kt)("a",{parentName:"li",href:"#fnref-2",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-3"},"definitely not an RHCP reference \ud83d\ude09",(0,s.kt)("a",{parentName:"li",href:"#fnref-3",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-4"},"one was not correct, thus the quotes",(0,s.kt)("a",{parentName:"li",href:"#fnref-4",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[8442],{3905:(a,e,t)=>{t.d(e,{Zo:()=>o,kt:()=>h});var n=t(7294);function s(a,e,t){return e in a?Object.defineProperty(a,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):a[e]=t,a}function m(a,e){var t=Object.keys(a);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(a);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(a,e).enumerable}))),t.push.apply(t,n)}return t}function p(a){for(var e=1;e=0||(s[t]=a[t]);return s}(a,e);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(a);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(a,t)&&(s[t]=a[t])}return s}var l=n.createContext({}),i=function(a){var e=n.useContext(l),t=e;return a&&(t="function"==typeof a?a(e):p(p({},e),a)),t},o=function(a){var e=i(a.components);return n.createElement(l.Provider,{value:e},a.children)},N="mdxType",c={inlineCode:"code",wrapper:function(a){var e=a.children;return n.createElement(n.Fragment,{},e)}},k=n.forwardRef((function(a,e){var t=a.components,s=a.mdxType,m=a.originalType,l=a.parentName,o=r(a,["components","mdxType","originalType","parentName"]),N=i(t),k=s,h=N["".concat(l,".").concat(k)]||N[k]||c[k]||m;return t?n.createElement(h,p(p({ref:e},o),{},{components:t})):n.createElement(h,p({ref:e},o))}));function h(a,e){var t=arguments,s=e&&e.mdxType;if("string"==typeof a||s){var m=t.length,p=new Array(m);p[0]=k;var r={};for(var l in e)hasOwnProperty.call(e,l)&&(r[l]=e[l]);r.originalType=a,r[N]="string"==typeof a?a:s,p[1]=r;for(var i=2;i{t.r(e),t.d(e,{assets:()=>l,contentTitle:()=>p,default:()=>c,frontMatter:()=>m,metadata:()=>r,toc:()=>i});var n=t(7462),s=(t(7294),t(3905));const m={id:"pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",tags:["java","recursion","exponential","greedy","dynamic-programming","top-down-dp","bottom-up-dp"],last_updated:{date:new Date("2023-08-17T00:00:00.000Z")}},p=void 0,r={unversionedId:"recursion/pyramid-slide-down",id:"recursion/pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",source:"@site/ib002/04-recursion/2023-08-17-pyramid-slide-down.md",sourceDirName:"04-recursion",slug:"/recursion/pyramid-slide-down",permalink:"/ib002/recursion/pyramid-slide-down",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/04-recursion/2023-08-17-pyramid-slide-down.md",tags:[{label:"java",permalink:"/ib002/tags/java"},{label:"recursion",permalink:"/ib002/tags/recursion"},{label:"exponential",permalink:"/ib002/tags/exponential"},{label:"greedy",permalink:"/ib002/tags/greedy"},{label:"dynamic-programming",permalink:"/ib002/tags/dynamic-programming"},{label:"top-down-dp",permalink:"/ib002/tags/top-down-dp"},{label:"bottom-up-dp",permalink:"/ib002/tags/bottom-up-dp"}],version:"current",lastUpdatedAt:1694109587,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"pyramid-slide-down",title:"Introduction to dynamic programming",description:"Solving a problem in different ways.\n",tags:["java","recursion","exponential","greedy","dynamic-programming","top-down-dp","bottom-up-dp"],last_updated:{date:"2023-08-17T00:00:00.000Z"}},sidebar:"autogeneratedBar",previous:{title:"Recursion and backtracking with Robot Karel",permalink:"/ib002/recursion/karel-1"},next:{title:"Red-Black Trees",permalink:"/ib002/category/red-black-trees"}},l={},i=[{value:"Problem",id:"problem",level:2},{value:"Solving the problem",id:"solving-the-problem",level:2},{value:"Na\xefve solution",id:"na\xefve-solution",level:2},{value:"Time complexity",id:"time-complexity",level:3},{value:"Greedy solution",id:"greedy-solution",level:2},{value:"Time complexity",id:"time-complexity-1",level:3},{value:"Running the tests",id:"running-the-tests",level:3},{value:"Top-down DP",id:"top-down-dp",level:2},{value:"Time complexity",id:"time-complexity-2",level:3},{value:"Memory complexity",id:"memory-complexity",level:3},{value:"Bottom-up DP",id:"bottom-up-dp",level:2},{value:"Time complexity",id:"time-complexity-3",level:3},{value:"Memory complexity",id:"memory-complexity-1",level:3},{value:"Summary",id:"summary",level:2}],o={toc:i},N="wrapper";function c(a){let{components:e,...t}=a;return(0,s.kt)(N,(0,n.Z)({},o,t,{components:e,mdxType:"MDXLayout"}),(0,s.kt)("p",null,"In this post we will try to solve one problem in different ways."),(0,s.kt)("h2",{id:"problem"},"Problem"),(0,s.kt)("p",null,"The problem we are going to solve is one of ",(0,s.kt)("em",{parentName:"p"},"CodeWars")," katas and is called\n",(0,s.kt)("a",{parentName:"p",href:"https://www.codewars.com/kata/551f23362ff852e2ab000037"},"Pyramid Slide Down"),"."),(0,s.kt)("p",null,"We are given a 2D array of integers and we are to find the ",(0,s.kt)("em",{parentName:"p"},"slide down"),".\n",(0,s.kt)("em",{parentName:"p"},"Slide down")," is a maximum sum of consecutive numbers from the top to the bottom."),(0,s.kt)("p",null,"Let's have a look at few examples. Consider the following pyramid:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 3\n 7 4\n 2 4 6\n8 5 9 3\n")),(0,s.kt)("p",null,"This pyramid has following slide down:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," *3\n *7 4\n 2 *4 6\n8 5 *9 3\n")),(0,s.kt)("p",null,"And its value is ",(0,s.kt)("inlineCode",{parentName:"p"},"23"),"."),(0,s.kt)("p",null,"We can also have a look at a ",(0,s.kt)("em",{parentName:"p"},"bigger")," example:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 75\n 95 64\n 17 47 82\n 18 35 87 10\n 20 4 82 47 65\n 19 1 23 3 34\n 88 2 77 73 7 63 67\n 99 65 4 28 6 16 70 92\n 41 41 26 56 83 40 80 70 33\n 41 48 72 33 47 32 37 16 94 29\n 53 71 44 65 25 43 91 52 97 51 14\n 70 11 33 28 77 73 17 78 39 68 17 57\n 91 71 52 38 17 14 91 43 58 50 27 29 48\n 63 66 4 68 89 53 67 30 73 16 69 87 40 31\n 4 62 98 27 23 9 70 98 73 93 38 53 60 4 23\n")),(0,s.kt)("p",null,"Slide down in this case is equal to ",(0,s.kt)("inlineCode",{parentName:"p"},"1074"),"."),(0,s.kt)("h2",{id:"solving-the-problem"},"Solving the problem"),(0,s.kt)("admonition",{type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"I will describe the following ways you can approach this problem and implement\nthem in ",(0,s.kt)("em",{parentName:"p"},"Java"),(0,s.kt)("sup",{parentName:"p",id:"fnref-1"},(0,s.kt)("a",{parentName:"sup",href:"#fn-1",className:"footnote-ref"},"1")),".")),(0,s.kt)("p",null,"For all of the following solutions I will be using basic ",(0,s.kt)("inlineCode",{parentName:"p"},"main")," function that\nwill output ",(0,s.kt)("inlineCode",{parentName:"p"},"true"),"/",(0,s.kt)("inlineCode",{parentName:"p"},"false")," based on the expected output of our algorithm. Any\nother differences will lie only in the solutions of the problem. You can see the\n",(0,s.kt)("inlineCode",{parentName:"p"},"main")," here:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},'public static void main(String[] args) {\n System.out.print("Test #1: ");\n System.out.println(longestSlideDown(new int[][] {\n { 3 },\n { 7, 4 },\n { 2, 4, 6 },\n { 8, 5, 9, 3 }\n }) == 23 ? "passed" : "failed");\n\n System.out.print("Test #2: ");\n System.out.println(longestSlideDown(new int[][] {\n { 75 },\n { 95, 64 },\n { 17, 47, 82 },\n { 18, 35, 87, 10 },\n { 20, 4, 82, 47, 65 },\n { 19, 1, 23, 75, 3, 34 },\n { 88, 2, 77, 73, 7, 63, 67 },\n { 99, 65, 4, 28, 6, 16, 70, 92 },\n { 41, 41, 26, 56, 83, 40, 80, 70, 33 },\n { 41, 48, 72, 33, 47, 32, 37, 16, 94, 29 },\n { 53, 71, 44, 65, 25, 43, 91, 52, 97, 51, 14 },\n { 70, 11, 33, 28, 77, 73, 17, 78, 39, 68, 17, 57 },\n { 91, 71, 52, 38, 17, 14, 91, 43, 58, 50, 27, 29, 48 },\n { 63, 66, 4, 68, 89, 53, 67, 30, 73, 16, 69, 87, 40, 31 },\n { 4, 62, 98, 27, 23, 9, 70, 98, 73, 93, 38, 53, 60, 4, 23 },\n }) == 1074 ? "passed" : "failed");\n}\n')),(0,s.kt)("h2",{id:"na\xefve-solution"},"Na\xefve solution"),(0,s.kt)("p",null,"Our na\xefve solution consists of trying out all the possible slides and finding\nthe one with maximum sum."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: We have gotten out of bounds, there's no reasonable value to\n // return, so we just return the \u2039MIN_VALUE\u203a to ensure that it cannot\n // be maximum.\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: Bottom of the pyramid, we just return the value, there's\n // nowhere to slide anymore.\n return pyramid[row][col];\n }\n\n // Otherwise we account for the current position and return maximum of the\n // available \u201cslides\u201d.\n return pyramid[row][col] + Math.max(\n longestSlideDown(pyramid, row + 1, col),\n longestSlideDown(pyramid, row + 1, col + 1));\n}\n\npublic static int longestSlideDown(int[][] pyramid) {\n // We start the slide in the top cell of the pyramid.\n return longestSlideDown(pyramid, 0, 0);\n}\n")),(0,s.kt)("p",null,"As you can see, we have 2 overloads:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"int longestSlideDown(int[][] pyramid);\nint longestSlideDown(int[][] pyramid, int row, int col);\n")),(0,s.kt)("p",null,"First one is used as a ",(0,s.kt)("em",{parentName:"p"},"public interface")," to the solution, you just pass in the\npyramid itself. Second one is the recursive \u201calgorithm\u201d that finds the slide\ndown."),(0,s.kt)("p",null,"It is a relatively simple solution\u2026 There's nothing to do at the bottom of the\npyramid, so we just return the value in the ",(0,s.kt)("em",{parentName:"p"},"cell"),". Otherwise we add it and try\nto slide down the available cells below the current row."),(0,s.kt)("h3",{id:"time-complexity"},"Time complexity"),(0,s.kt)("p",null,"If you get the source code and run it yourself, it runs rather fine\u2026 I hope you\nare wondering about the time complexity of the proposed solution and, since it\nreally is a na\xefve solution, the time complexity is pretty bad. Let's find the\nworst case scenario."),(0,s.kt)("p",null,"Let's start with the first overload:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid) {\n return longestSlideDown(pyramid, 0, 0);\n}\n")),(0,s.kt)("p",null,"There's not much to do here, so we can safely say that the time complexity of\nthis function is bounded by ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"))))),", where ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T")))))," is our second overload. This\ndoesn't tell us anything, so let's move on to the second overload where we are\ngoing to define the ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))," function."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: We have gotten out of bounds, there's no reasonable value to\n // return, so we just return the \u2039MIN_VALUE\u203a to ensure that it cannot\n // be maximum.\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: Bottom of the pyramid, we just return the value, there's\n // nowhere to slide anymore.\n return pyramid[row][col];\n }\n\n // Otherwise we account for the current position and return maximum of the\n // available \u201cslides\u201d.\n return pyramid[row][col] + Math.max(\n longestSlideDown(pyramid, row + 1, col),\n longestSlideDown(pyramid, row + 1, col + 1));\n}\n")),(0,s.kt)("p",null,"Fun fact is that the whole \u201calgorithm\u201d consists of just 2 ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statements\nand nothing else. Let's dissect them!"),(0,s.kt)("p",null,"First ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statement is the base case, so it has a constant time complexity."),(0,s.kt)("p",null,"Second one a bit tricky. We add two numbers together, which we'll consider as\nconstant, but for the right part of the expression we take maximum from the left\nand right paths. OK\u2026 So what happens? We evaluate the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown")," while\nchoosing the under and right both. They are separate computations though, so we\nare branching from each call of ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown"),", unless it's a base case."),(0,s.kt)("p",null,"What does that mean for us then? We basically get"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"{"),(0,s.kt)("mtable",{parentName:"mrow",rowspacing:"0.36em",columnalign:"left left",columnspacing:"1em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mn",{parentName:"mstyle"},"1"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mtext",{parentName:"mrow"},",\xa0if\xa0"),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mn",{parentName:"mrow"},"1"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"1"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"false"},(0,s.kt)("mtext",{parentName:"mstyle"},",\xa0otherwise"))))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(y) = \\begin{cases} 1 & \\text{, if } y = rows \\\\ 1 + 2 \\cdot T(y + 1) & \\text{, otherwise} \\end{cases}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},(0,s.kt)("span",{parentName:"span",className:"delimsizing size4"},"{")),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.69em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.69em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"1"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.25em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"1"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"1"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.19em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"arraycolsep",style:{width:"1em"}}),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.69em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.69em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord text"},(0,s.kt)("span",{parentName:"span",className:"mord"},",\xa0if\xa0")),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.25em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.008em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord text"},(0,s.kt)("span",{parentName:"span",className:"mord"},",\xa0otherwise"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.19em"}},(0,s.kt)("span",{parentName:"span"}))))))),(0,s.kt)("span",{parentName:"span",className:"mclose nulldelimiter"}))))))),(0,s.kt)("p",null,"That looks rather easy to compute, isn't it? If you sum it up, you'll get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"T"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mo",{parentName:"mrow"},"\u2208"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("msup",{parentName:"mrow"},(0,s.kt)("mn",{parentName:"msup"},"2"),(0,s.kt)("mrow",{parentName:"msup"},(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"))),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"T(rows) \\in \\mathcal{O}(2^{rows})")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"T"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"\u2208"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.7144em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.113em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"s"))))))))),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"If you wonder why, I'll try to describe it intuitively:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"In each call to ",(0,s.kt)("inlineCode",{parentName:"li"},"longestSlideDown")," we do some work in constant time,\nregardless of being in the base case. Those are the ",(0,s.kt)("inlineCode",{parentName:"li"},"1"),"s in both cases."),(0,s.kt)("li",{parentName:"ol"},"If we are not in the base case, we move one row down ",(0,s.kt)("strong",{parentName:"li"},"twice"),". That's how we\nobtained ",(0,s.kt)("inlineCode",{parentName:"li"},"2 *")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"y + 1")," in the ",(0,s.kt)("em",{parentName:"li"},"otherwise")," case."),(0,s.kt)("li",{parentName:"ol"},"We move row-by-row, so we move down ",(0,s.kt)("inlineCode",{parentName:"li"},"y"),"-times and each call splits to two\nsubtrees."),(0,s.kt)("li",{parentName:"ol"},"Overall, if we were to represent the calls as a tree, we would get a full\nbinary tree of height ",(0,s.kt)("inlineCode",{parentName:"li"},"y"),", in each node we do some work in constant time,\ntherefore we can just sum the ones.")),(0,s.kt)("admonition",{type:"warning"},(0,s.kt)("p",{parentName:"admonition"},"It would've been more complicated to get an exact result. In the equation above\nwe are assuming that the width of the pyramid is bound by the height.")),(0,s.kt)("p",null,"Hopefully we can agree that this is not the best we can do. \ud83d\ude09"),(0,s.kt)("h2",{id:"greedy-solution"},"Greedy solution"),(0,s.kt)("p",null,"We will try to optimize it a bit. Let's start with a relatively simple ",(0,s.kt)("em",{parentName:"p"},"greedy"),"\napproach."),(0,s.kt)("admonition",{title:"Greedy algorithms",type:"info"},(0,s.kt)("p",{parentName:"admonition"},(0,s.kt)("em",{parentName:"p"},"Greedy algorithms")," can be described as algorithms that decide the action on the\noptimal option at the moment.")),(0,s.kt)("p",null,"We can try to adjust the na\xefve solution. The most problematic part are the\nrecursive calls. Let's apply the greedy approach there:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid, int row, int col) {\n if (row == pyramid.length - 1) {\n // BASE: We're at the bottom\n return pyramid[row][col];\n }\n\n if (col + 1 >= pyramid[row + 1].length\n || pyramid[row + 1][col] > pyramid[row + 1][col + 1]) {\n // If we cannot go right or it's not feasible, we continue to the left.\n return pyramid[row][col] + longestSlideDown(pyramid, row + 1, col);\n }\n\n // Otherwise we just move to the right.\n return pyramid[row][col] + longestSlideDown(pyramid, row + 1, col + 1);\n}\n")),(0,s.kt)("p",null,"OK, if we cannot go right ",(0,s.kt)("strong",{parentName:"p"},"or")," the right path adds smaller value to the sum,\nwe simply go left."),(0,s.kt)("h3",{id:"time-complexity-1"},"Time complexity"),(0,s.kt)("p",null,"We have switched from ",(0,s.kt)("em",{parentName:"p"},"adding the maximum")," to ",(0,s.kt)("em",{parentName:"p"},"following the \u201cbigger\u201d path"),", so\nwe improved the time complexity tremendously. We just go down the pyramid all\nthe way to the bottom. Therefore we are getting:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"We have managed to convert our exponential solution into a linear one."),(0,s.kt)("h3",{id:"running-the-tests"},"Running the tests"),(0,s.kt)("p",null,"However, if we run the tests, we notice that the second test failed:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},"Test #1: passed\nTest #2: failed\n")),(0,s.kt)("p",null,"What's going on? Well, we have improved the time complexity, but greedy\nalgorithms are not the ideal solution to ",(0,s.kt)("strong",{parentName:"p"},"all")," problems. In this case there\nmay be a solution that is bigger than the one found using the greedy algorithm."),(0,s.kt)("p",null,"Imagine the following pyramid:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"}," 1\n 2 3\n 5 6 7\n 8 9 10 11\n99 13 14 15 16\n")),(0,s.kt)("p",null,"We start at the top:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"1"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"2")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"3"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"3")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"3"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"6")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"7"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"7")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"7"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"10")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"11"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"11")," looks better, so we\nchoose it."),(0,s.kt)("li",{parentName:"ol"},"Current cell: ",(0,s.kt)("inlineCode",{parentName:"li"},"11"),", we can choose from ",(0,s.kt)("inlineCode",{parentName:"li"},"15")," and ",(0,s.kt)("inlineCode",{parentName:"li"},"16"),", ",(0,s.kt)("inlineCode",{parentName:"li"},"16")," looks better, so\nwe choose it.")),(0,s.kt)("p",null,"Our final sum is: ",(0,s.kt)("inlineCode",{parentName:"p"},"1 + 3 + 7 + 11 + 16 = 38"),", but in the bottom left cell we\nhave a ",(0,s.kt)("inlineCode",{parentName:"p"},"99")," that is bigger than our whole sum."),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"Dijkstra's algorithm is a greedy algorithm too, try to think why it is correct.")),(0,s.kt)("h2",{id:"top-down-dp"},"Top-down DP"),(0,s.kt)("p",null,(0,s.kt)("em",{parentName:"p"},"Top-down dynamic programming")," is probably the most common approach, since (at\nleast looks like) is the easiest to implement. The whole point is avoiding the\nunnecessary computations that we have already done."),(0,s.kt)("p",null,"In our case, we can use our na\xefve solution and put a ",(0,s.kt)("em",{parentName:"p"},"cache")," on top of it that\nwill make sure, we don't do unnecessary calculations."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"// This \u201cstructure\u201d is required, since I have decided to use \u2039TreeMap\u203a which\n// requires the ordering on the keys. It represents one position in the pyramid.\nrecord Position(int row, int col) implements Comparable {\n public int compareTo(Position r) {\n if (row != r.row) {\n return Integer.valueOf(row).compareTo(r.row);\n }\n\n if (col != r.col) {\n return Integer.valueOf(col).compareTo(r.col);\n }\n\n return 0;\n }\n}\n\npublic static int longestSlideDown(\n int[][] pyramid,\n TreeMap cache,\n Position position) {\n int row = position.row;\n int col = position.col;\n\n if (row >= pyramid.length || col < 0 || col >= pyramid[row].length) {\n // BASE: out of bounds\n return Integer.MIN_VALUE;\n }\n\n if (row == pyramid.length - 1) {\n // BASE: bottom of the pyramid\n return pyramid[position.row][position.col];\n }\n\n if (!cache.containsKey(position)) {\n // We haven't computed the position yet, so we run the same \u201cformula\u201d as\n // in the na\xefve version \xbband\xab we put calculated slide into the cache.\n // Next time we want the slide down from given position, it will be just\n // retrieved from the cache.\n int slideDown = Math.max(\n longestSlideDown(pyramid, cache, new Position(row + 1, col)),\n longestSlideDown(pyramid, cache, new Position(row + 1, col + 1)));\n cache.put(position, pyramid[row][col] + slideDown);\n }\n\n return cache.get(position);\n}\n\npublic static int longestSlideDown(int[][] pyramid) {\n // At the beginning we need to create a cache and share it across the calls.\n TreeMap cache = new TreeMap<>();\n return longestSlideDown(pyramid, cache, new Position(0, 0));\n}\n")),(0,s.kt)("p",null,"You have probably noticed that ",(0,s.kt)("inlineCode",{parentName:"p"},"record Position")," have appeared. Since we are\ncaching the already computed values, we need a \u201creasonable\u201d key. In this case we\nshare the cache only for one ",(0,s.kt)("em",{parentName:"p"},"run")," (i.e. pyramid) of the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown"),", so\nwe can cache just with the indices within the pyramid, i.e. the ",(0,s.kt)("inlineCode",{parentName:"p"},"Position"),"."),(0,s.kt)("admonition",{title:"Record",type:"tip"},(0,s.kt)("p",{parentName:"admonition"},(0,s.kt)("em",{parentName:"p"},"Record")," is relatively new addition to the Java language. It is basically an\nimmutable structure with implicitly defined ",(0,s.kt)("inlineCode",{parentName:"p"},".equals()"),", ",(0,s.kt)("inlineCode",{parentName:"p"},".hashCode()"),",\n",(0,s.kt)("inlineCode",{parentName:"p"},".toString()")," and getters for the attributes.")),(0,s.kt)("p",null,"Because of the choice of ",(0,s.kt)("inlineCode",{parentName:"p"},"TreeMap"),", we had to additionally define the ordering\non it."),(0,s.kt)("p",null,"In the ",(0,s.kt)("inlineCode",{parentName:"p"},"longestSlideDown")," you can notice that the computation which used to be\nat the end of the na\xefve version above, is now wrapped in an ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," statement that\nchecks for the presence of the position in the cache and computes the slide down\njust when it's needed."),(0,s.kt)("h3",{id:"time-complexity-2"},"Time complexity"),(0,s.kt)("p",null,"If you think that evaluating time complexity for this approach is a bit more\ntricky, you are right. Keeping the cache in mind, it is not the easiest thing\nto do. However there are some observations that might help us figure this out:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},"Slide down from each position is calculated only once."),(0,s.kt)("li",{parentName:"ol"},"Once calculated, we use the result from the cache.")),(0,s.kt)("p",null,"Knowing this, we still cannot, at least easily, describe the time complexity of\nfinding the best slide down from a specific position, ",(0,s.kt)("strong",{parentName:"p"},"but")," we can bound it\nfrom above for the ",(0,s.kt)("strong",{parentName:"p"},"whole")," run from the top. Now the question is how we can do\nthat!"),(0,s.kt)("p",null,"Overall we are doing the same things for almost",(0,s.kt)("sup",{parentName:"p",id:"fnref-2"},(0,s.kt)("a",{parentName:"sup",href:"#fn-2",className:"footnote-ref"},"2"))," all of the positions within\nthe pyramid:"),(0,s.kt)("ol",null,(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},"We calculate and store it (using the partial results stored in cache). This\nis done only once."),(0,s.kt)("p",{parentName:"li"},"For each calculation we take 2 values from the cache and insert one value.\nBecause we have chosen ",(0,s.kt)("inlineCode",{parentName:"p"},"TreeMap"),", these 3 operations have logarithmic time\ncomplexity and therefore this step is equivalent to ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mn",{parentName:"mrow"},"3"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"3 \\cdot \\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"3"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),"."),(0,s.kt)("p",{parentName:"li"},"However for the sake of simplicity, we are going to account only for the\ninsertion, the reason is rather simple, if we include the 2 retrievals here,\nit will be interleaved with the next step, therefore it is easier to keep the\nretrievals in the following point."),(0,s.kt)("admonition",{parentName:"li",type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"You might have noticed it's still not that easy, cause we're not having full\ncache right from the beginning, but the sum of those logarithms cannot be\nexpressed in a nice way, so taking the upper bound, i.e. expecting the cache\nto be full at all times, is the best option for nice and readable complexity\nof the whole approach.")),(0,s.kt)("p",{parentName:"li"},"Our final upper bound of this work is therefore ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),".")),(0,s.kt)("li",{parentName:"ol"},(0,s.kt)("p",{parentName:"li"},"We retrieve it from the cache. Same as in first point, but only twice, so we\nget ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mrow",{parentName:"msub"},(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061")),(0,s.kt)("mn",{parentName:"msub"},"2")),(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"2 \\cdot \\log_2{n}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9386em",verticalAlign:"-0.2441em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.207em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.4559em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"2")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2441em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))),". "),(0,s.kt)("admonition",{parentName:"li",type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"It's done twice because of the ",(0,s.kt)("inlineCode",{parentName:"p"},".containsKey()")," in the ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," condition.")))),(0,s.kt)("p",null,"Okay, we have evaluated work done for each of the cells in the pyramid and now\nwe need to put it together."),(0,s.kt)("p",null,"Let's split the time complexity of our solution into two operands:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(r + s)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"r")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"r")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))))," will represent the ",(0,s.kt)("em",{parentName:"p"},"actual")," calculation of the cells and ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"s")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"s")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))))," will represent\nthe additional retrievals on top of the calculation."),(0,s.kt)("p",null,"We calculate the values only ",(0,s.kt)("strong",{parentName:"p"},"once"),", therefore we can safely agree on:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"r"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} r &= n \\cdot \\log{n} \\\\ \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1.5em",verticalAlign:"-0.5em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.16em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.5em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.16em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.5em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("p",null,"What about the ",(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"s")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"s")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))))," though? Key observation here is the fact that we have 2\nlookups on the tree in each of them ",(0,s.kt)("strong",{parentName:"p"},"and")," we do it twice, cause each cell has\nat most 2 parents:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"("),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",fence:"true"},")")))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"4"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} s &= n \\cdot 2 \\cdot \\left( 2 \\cdot \\log{n} \\right) \\\\ s &= 4 \\cdot n \\cdot \\log{n} \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose delimcenter",style:{top:"0em"}},")")))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"4"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"You might've noticed that lookups actually take more time than the construction\nof the results. This is not entirely true, since we have included the\n",(0,s.kt)("inlineCode",{parentName:"p"},".containsKey()")," and ",(0,s.kt)("inlineCode",{parentName:"p"},".get()")," from the ",(0,s.kt)("inlineCode",{parentName:"p"},"return")," statement in the second part."),(0,s.kt)("p",{parentName:"admonition"},"If we were to represent this more precisely, we could've gone with:"),(0,s.kt)("div",{parentName:"admonition",className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mtable",{parentName:"semantics",rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em"},(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"r"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"3"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"))))),(0,s.kt)("mtr",{parentName:"mtable"},(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mi",{parentName:"mstyle"},"s"))),(0,s.kt)("mtd",{parentName:"mtr"},(0,s.kt)("mstyle",{parentName:"mtd",scriptlevel:"0",displaystyle:"true"},(0,s.kt)("mrow",{parentName:"mstyle"},(0,s.kt)("mrow",{parentName:"mrow"}),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n")))))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\begin{align*} r &= 3 \\cdot n \\cdot \\log{n} \\\\ s &= 2 \\cdot n \\cdot \\log{n} \\end{align*}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3em",verticalAlign:"-1.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mtable"},(0,s.kt)("span",{parentName:"span",className:"col-align-r"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"col-align-l"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.75em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-3.91em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"3"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))),(0,s.kt)("span",{parentName:"span",style:{top:"-2.41em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord"}),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"="),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.25em"}},(0,s.kt)("span",{parentName:"span"})))))))))))),(0,s.kt)("p",{parentName:"admonition"},"On the other hand we are summing both numbers together, therefore in the end it\ndoesn't really matter."),(0,s.kt)("p",{parentName:"admonition"},"(",(0,s.kt)("em",{parentName:"p"},"Feel free to compare the sums of both \u201csplits\u201d."),")")),(0,s.kt)("p",null,"And so our final time complexity for the whole ",(0,s.kt)("em",{parentName:"p"},"top-down dynamic programming"),"\napproach is:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"4"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mn",{parentName:"mrow"},"5"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mspace",{parentName:"mrow",linebreak:"newline"}),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,s.kt)("mi",{parentName:"mrow"},"log"),(0,s.kt)("mo",{parentName:"mrow"},"\u2061"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(r + s) \\\\ \\mathcal{O}(n \\cdot \\log{n} + 4 \\cdot n \\cdot \\log{n}) \\\\ \\mathcal{O}(5 \\cdot n \\cdot \\log{n}) \\\\ \\mathcal{O}(n \\cdot \\log{n})")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"4"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4445em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord"},"5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4445em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")),(0,s.kt)("span",{parentName:"span",className:"mspace newline"}),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mop"},"lo",(0,s.kt)("span",{parentName:"span",style:{marginRight:"0.01389em"}},"g")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"As you can see, this is worse than our ",(0,s.kt)("em",{parentName:"p"},"greedy")," solution that was incorrect, but\nit's better than the ",(0,s.kt)("em",{parentName:"p"},"na\xefve")," one."),(0,s.kt)("h3",{id:"memory-complexity"},"Memory complexity"),(0,s.kt)("p",null,"With this approach we need to talk about the memory complexity too, because we\nhave introduced cache. If you think that the memory complexity is linear to the\ninput, you are right. We start at the top and try to find each and every slide\ndown. At the end we get the final result for ",(0,s.kt)("inlineCode",{parentName:"p"},"new Position(0, 0)"),", so we need to\ncompute everything below."),(0,s.kt)("p",null,"That's how we obtain:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"n")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"n")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n")))))," represents the total amount of cells in the pyramid, i.e."),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("munderover",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"munderover"},"\u2211"),(0,s.kt)("mrow",{parentName:"munderover"},(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow"},"="),(0,s.kt)("mn",{parentName:"mrow"},"0")),(0,s.kt)("mrow",{parentName:"munderover"},(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"p"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"y"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"r"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"a"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"m"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"."),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"l"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"g"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"h")),(0,s.kt)("mo",{parentName:"mrow"},"\u2212"),(0,s.kt)("mn",{parentName:"mrow"},"1"))),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"p"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"y"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"r"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"a"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"m"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"i"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"d")),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"["),(0,s.kt)("mi",{parentName:"mrow"},"y"),(0,s.kt)("mo",{parentName:"mrow",fence:"true"},"]")),(0,s.kt)("mrow",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"."),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"l"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"e"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"n"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"g"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"t"),(0,s.kt)("mi",{parentName:"mrow",mathvariant:"monospace"},"h"))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\sum_{y=0}^{\\mathtt{pyramid.length} - 1} \\mathtt{pyramid}\\left[y\\right]\\mathtt{.length}")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"3.2709em",verticalAlign:"-1.4032em"}}),(0,s.kt)("span",{parentName:"span",className:"mop op-limits"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.8677em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-1.8829em",marginLeft:"0em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mrel mtight"},"="),(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,s.kt)("span",{parentName:"span",style:{top:"-3.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span"},(0,s.kt)("span",{parentName:"span",className:"mop op-symbol large-op"},"\u2211"))),(0,s.kt)("span",{parentName:"span",style:{top:"-4.3666em",marginLeft:"0em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt mtight"},"pyramid.length")),(0,s.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.4032em"}},(0,s.kt)("span",{parentName:"span"}))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt"},"pyramid")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},(0,s.kt)("span",{parentName:"span",className:"mopen delimcenter",style:{top:"0em"}},"["),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"y"),(0,s.kt)("span",{parentName:"span",className:"mclose delimcenter",style:{top:"0em"}},"]")),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathtt"},".length"))))))),(0,s.kt)("admonition",{type:"caution"},(0,s.kt)("p",{parentName:"admonition"},"If you're wondering whether it's correct because of the second ",(0,s.kt)("inlineCode",{parentName:"p"},"if")," in our\nfunction, your guess is right. However we are expressing the complexity in the\nBachmann-Landau notation, so we care about the ",(0,s.kt)("strong",{parentName:"p"},"upper bound"),", not the exact\nnumber.")),(0,s.kt)("admonition",{title:"Can this be optimized?",type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"Yes, it can! Try to think about a way, how can you minimize the memory\ncomplexity of this approach. I'll give you a hint:"),(0,s.kt)("div",{parentName:"admonition",className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"))))))),(0,s.kt)("h2",{id:"bottom-up-dp"},"Bottom-up DP"),(0,s.kt)("p",null,"If you try to think in depth about the top-down DP solution, you might notice\nthat the ",(0,s.kt)("em",{parentName:"p"},"core")," of it stands on caching the calculations that have been already\ndone on the lower \u201clevels\u201d of the pyramid. Our bottom-up implementation will be\nusing this fact!"),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"As I have said in the ",(0,s.kt)("em",{parentName:"p"},"top-down DP")," section, it is the easiest way to implement\nDP (unless the cached function has complicated parameters, in that case it might\nget messy)."),(0,s.kt)("p",{parentName:"admonition"},"Bottom-up dynamic programming can be more effective, but may be more complicated\nto implement right from the beginning.")),(0,s.kt)("p",null,"Let's see how we can implement it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-java"},"public static int longestSlideDown(int[][] pyramid) {\n // In the beginning we declare new array. At this point it is easier to just\n // work with the one dimension, i.e. just allocating the space for the rows.\n int[][] slideDowns = new int[pyramid.length][];\n\n // Bottom row gets just copied, there's nothing else to do\u2026 It's the base\n // case.\n slideDowns[pyramid.length - 1] = Arrays.copyOf(pyramid[pyramid.length - 1],\n pyramid[pyramid.length - 1].length);\n\n // Then we need to propagate the found slide downs for each of the levels\n // above.\n for (int y = pyramid.length - 2; y >= 0; --y) {\n // We start by copying the values lying in the row we're processing.\n // They get included in the final sum and we need to allocate the space\n // for the precalculated slide downs anyways.\n int[] row = Arrays.copyOf(pyramid[y], pyramid[y].length);\n\n // At this we just need to \u201cfetch\u201d the partial results from \u201cneighbours\u201d\n for (int x = 0; x < row.length; ++x) {\n // We look under our position, since we expect the rows to get\n // shorter, we can safely assume such position exists.\n int under = slideDowns[y + 1][x];\n\n // Then we have a look to the right, such position doesn't have to\n // exist, e.g. on the right edge, so we validate the index, and if\n // it doesn't exist, we just assign minimum of the \u2039int\u203a which makes\n // sure that it doesn't get picked in the \u2039Math.max()\u203a call.\n int toRight = x + 1 < slideDowns[y + 1].length\n ? slideDowns[y + 1][x + 1]\n : Integer.MIN_VALUE;\n\n // Finally we add the best choice at this point.\n row[x] += Math.max(under, toRight);\n }\n\n // And save the row we've just calculated partial results for to the\n // \u201ctable\u201d.\n slideDowns[y] = row;\n }\n\n // At the end we can find our seeked slide down at the top cell.\n return slideDowns[0][0];\n}\n")),(0,s.kt)("p",null,"I've tried to explain the code as much as possible within the comments, since it\nmight be more beneficial to see right next to the \u201coffending\u201d lines."),(0,s.kt)("p",null,"As you can see, in this approach we go from the other side",(0,s.kt)("sup",{parentName:"p",id:"fnref-3"},(0,s.kt)("a",{parentName:"sup",href:"#fn-3",className:"footnote-ref"},"3")),", the bottom of\nthe pyramid and propagate the partial results up."),(0,s.kt)("admonition",{type:"info"},(0,s.kt)("mdxAdmonitionTitle",{parentName:"admonition"},"How is this different from the ",(0,s.kt)("em",{parentName:"mdxAdmonitionTitle"},"greedy")," solution???"),(0,s.kt)("p",{parentName:"admonition"},"If you try to compare them, you might find a very noticable difference. The\ngreedy approach is going from the top to the bottom without ",(0,s.kt)("strong",{parentName:"p"},"any")," knowledge of\nwhat's going on below. On the other hand, bottom-up DP is going from the bottom\n(",(0,s.kt)("em",{parentName:"p"},"DUH\u2026"),") and ",(0,s.kt)("strong",{parentName:"p"},"propagates")," the partial results to the top. The propagation is\nwhat makes sure that at the top I don't choose the best ",(0,s.kt)("strong",{parentName:"p"},"local")," choice, but\nthe best ",(0,s.kt)("strong",{parentName:"p"},"overall")," result I can achieve.")),(0,s.kt)("h3",{id:"time-complexity-3"},"Time complexity"),(0,s.kt)("p",null,"Time complexity of this solution is rather simple. We allocate an array for the\nrows and then for each row, we copy it and adjust the partial results. Doing\nthis we get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"r"),(0,s.kt)("mi",{parentName:"mrow"},"o"),(0,s.kt)("mi",{parentName:"mrow"},"w"),(0,s.kt)("mi",{parentName:"mrow"},"s"),(0,s.kt)("mo",{parentName:"mrow"},"+"),(0,s.kt)("mn",{parentName:"mrow"},"2"),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(rows + 2n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"ro"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02691em"}},"w"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"s"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,s.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},"2"),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("p",null,"Of course, this is an upper bound, since we iterate through the bottom row only\nonce."),(0,s.kt)("h3",{id:"memory-complexity-1"},"Memory complexity"),(0,s.kt)("p",null,"We're allocating an array for the pyramid ",(0,s.kt)("strong",{parentName:"p"},"again")," for our partial results, so\nwe get:"),(0,s.kt)("div",{className:"math math-display"},(0,s.kt)("span",{parentName:"div",className:"katex-display"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow",mathvariant:"script"},"O"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"n"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\mathcal{O}(n)")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathcal",style:{marginRight:"0.02778em"}},"O"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"n"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")")))))),(0,s.kt)("admonition",{type:"tip"},(0,s.kt)("p",{parentName:"admonition"},"If we were writing this in C++ or Rust, we could've avoided that, but not\nreally."),(0,s.kt)("p",{parentName:"admonition"},"C++ would allow us to ",(0,s.kt)("strong",{parentName:"p"},"copy")," the pyramid rightaway into the parameter, so we\nwould be able to directly change it. However it's still a copy, even though we\ndon't need to allocate anything ourselves. It's just implicitly done for us."),(0,s.kt)("p",{parentName:"admonition"},"Rust is more funny in this case. If the pyramids weren't used after the call of\n",(0,s.kt)("inlineCode",{parentName:"p"},"longest_slide_down"),", it would simply ",(0,s.kt)("strong",{parentName:"p"},"move")," them into the functions. If they\nwere used afterwards, the compiler would force you to either borrow it, or\n",(0,s.kt)("em",{parentName:"p"},"clone-and-move")," for the function."),(0,s.kt)("hr",{parentName:"admonition"}),(0,s.kt)("p",{parentName:"admonition"},"Since we're doing it in Java, we get a reference to the ",(0,s.kt)("em",{parentName:"p"},"original")," array and we\ncan't do whatever we want with it.")),(0,s.kt)("h2",{id:"summary"},"Summary"),(0,s.kt)("p",null,"And we've finally reached the end. We have seen 4 different \u201csolutions\u201d",(0,s.kt)("sup",{parentName:"p",id:"fnref-4"},(0,s.kt)("a",{parentName:"sup",href:"#fn-4",className:"footnote-ref"},"4"))," of\nthe same problem using different approaches. Different approaches follow the\norder in which you might come up with them, each approach influences its\nsuccessor and represents the way we can enhance the existing implementation."),(0,s.kt)("hr",null),(0,s.kt)("admonition",{title:"source",type:"info"},(0,s.kt)("p",{parentName:"admonition"},"You can find source code referenced in the text\n",(0,s.kt)("a",{parentName:"p",href:"pathname:///files/ib002/recursion/pyramid-slide-down.tar.gz"},"here"),".")),(0,s.kt)("div",{className:"footnotes"},(0,s.kt)("hr",{parentName:"div"}),(0,s.kt)("ol",{parentName:"div"},(0,s.kt)("li",{parentName:"ol",id:"fn-1"},"cause why not, right!?",(0,s.kt)("a",{parentName:"li",href:"#fnref-1",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-2"},"except the bottom row",(0,s.kt)("a",{parentName:"li",href:"#fnref-2",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-3"},"definitely not an RHCP reference \ud83d\ude09",(0,s.kt)("a",{parentName:"li",href:"#fnref-3",className:"footnote-backref"},"\u21a9")),(0,s.kt)("li",{parentName:"ol",id:"fn-4"},"one was not correct, thus the quotes",(0,s.kt)("a",{parentName:"li",href:"#fnref-4",className:"footnote-backref"},"\u21a9")))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/834ed470.690ec9f0.js b/assets/js/834ed470.668efafa.js similarity index 98% rename from assets/js/834ed470.690ec9f0.js rename to assets/js/834ed470.668efafa.js index 8e5c00a..1439636 100644 --- a/assets/js/834ed470.690ec9f0.js +++ b/assets/js/834ed470.668efafa.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3223],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=o,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={id:"ib002-intro",title:"Introduction",slug:"/"},i=void 0,s={unversionedId:"ib002-intro",id:"ib002-intro",title:"Introduction",description:"In this part you can find \u201crandom\u201d additional materials I have written over the",source:"@site/ib002/00-intro-ib002.md",sourceDirName:".",slug:"/",permalink:"/ib002/",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/00-intro-ib002.md",tags:[],version:"current",lastUpdatedAt:1694108971,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"ib002-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Algorithms and Correctness",permalink:"/ib002/category/algorithms-and-correctness"}},c={},l=[],u={toc:l},p="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"In this part you can find \u201crandom\u201d additional materials I have written over the\ncourse of teaching ",(0,o.kt)("em",{parentName:"p"},"Algorithms and data structures I"),"."),(0,o.kt)("p",null,"It is a various mix of stuff that may have been produced as a follow-up on some\nquestion asked at the seminar or spontanously."),(0,o.kt)("p",null,"If you have some ideas for posts, please do not hesitate to submit them as issues\nin the linked ",(0,o.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/xfocko/kb/issues"},"GitLab"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[3223],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},p="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,c=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),p=l(r),d=o,m=p["".concat(c,".").concat(d)]||p[d]||f[d]||a;return r?n.createElement(m,i(i({ref:t},u),{},{components:r})):n.createElement(m,i({ref:t},u))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[p]="string"==typeof e?e:o,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>f,frontMatter:()=>a,metadata:()=>s,toc:()=>l});var n=r(7462),o=(r(7294),r(3905));const a={id:"ib002-intro",title:"Introduction",slug:"/"},i=void 0,s={unversionedId:"ib002-intro",id:"ib002-intro",title:"Introduction",description:"In this part you can find \u201crandom\u201d additional materials I have written over the",source:"@site/ib002/00-intro-ib002.md",sourceDirName:".",slug:"/",permalink:"/ib002/",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/ib002/00-intro-ib002.md",tags:[],version:"current",lastUpdatedAt:1694109587,formattedLastUpdatedAt:"Sep 7, 2023",sidebarPosition:0,frontMatter:{id:"ib002-intro",title:"Introduction",slug:"/"},sidebar:"autogeneratedBar",next:{title:"Algorithms and Correctness",permalink:"/ib002/category/algorithms-and-correctness"}},c={},l=[],u={toc:l},p="wrapper";function f(e){let{components:t,...r}=e;return(0,o.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"In this part you can find \u201crandom\u201d additional materials I have written over the\ncourse of teaching ",(0,o.kt)("em",{parentName:"p"},"Algorithms and data structures I"),"."),(0,o.kt)("p",null,"It is a various mix of stuff that may have been produced as a follow-up on some\nquestion asked at the seminar or spontanously."),(0,o.kt)("p",null,"If you have some ideas for posts, please do not hesitate to submit them as issues\nin the linked ",(0,o.kt)("a",{parentName:"p",href:"https://gitlab.fi.muni.cz/xfocko/kb/issues"},"GitLab"),"."))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/83bf91d3.21975b05.js b/assets/js/83bf91d3.193b1d35.js similarity index 99% rename from assets/js/83bf91d3.21975b05.js rename to assets/js/83bf91d3.193b1d35.js index ef97441..9fa22c0 100644 --- a/assets/js/83bf91d3.21975b05.js +++ b/assets/js/83bf91d3.193b1d35.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7823],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=p(n),h=a,d=m["".concat(l,".").concat(h)]||m[h]||c[h]||o;return n?r.createElement(d,i(i({ref:t},u),{},{components:n})):r.createElement(d,i({ref:t},u))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:a,i[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const o={title:"Submitting merge requests"},i="Submitting merge requests for review",s={unversionedId:"mr",id:"mr",title:"Submitting merge requests",description:"This tutorial aims to show you how to follow basic git workflow and submit changes",source:"@site/pb071/mr.md",sourceDirName:".",slug:"/mr",permalink:"/pb071/mr",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/mr.md",tags:[],version:"current",lastUpdatedAt:1694108971,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{title:"Submitting merge requests"},sidebar:"autogeneratedBar",previous:{title:"Practice exam C",permalink:"/pb071/pexam/cams"}},l={},p=[{value:"Tutorial",id:"tutorial",level:2},{value:"Step #1 - Starting from the clean repository",id:"step-1---starting-from-the-clean-repository",level:3},{value:"Step #2 - Create new branch",id:"step-2---create-new-branch",level:3},{value:"Step #3 - Do the assignment",id:"step-3---do-the-assignment",level:3},{value:"Step #4 - Commit and upload the changes to GitLab",id:"step-4---commit-and-upload-the-changes-to-gitlab",level:3},{value:"Step #5 - Creating a merge request manually",id:"step-5---creating-a-merge-request-manually",level:3},{value:"Step #6 - Set assignees",id:"step-6---set-assignees",level:3},{value:"Step #7 - Return to default branch",id:"step-7---return-to-default-branch",level:3}],u={toc:p},m="wrapper";function c(e){let{components:t,...n}=e;return(0,a.kt)(m,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"submitting-merge-requests-for-review"},"Submitting merge requests for review"),(0,a.kt)("p",null,"This tutorial aims to show you how to follow basic git workflow and submit changes\nthrough ",(0,a.kt)("em",{parentName:"p"},"Merge Requests")," for review."),(0,a.kt)("p",null,"The rudimentary idea behind aims for changes to be present on a separate branch\nthat is supposedly ",(0,a.kt)("em",{parentName:"p"},"merged")," into the default branch. Till then changes can be reviewed\non ",(0,a.kt)("em",{parentName:"p"},"Merge Request")," and additional changes may be made based on the reviews. Once\nthe changes satisfy requirements, the merge request is merged."),(0,a.kt)("h2",{id:"tutorial"},"Tutorial"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Use this tutorial only for bonus assignments ",(0,a.kt)("strong",{parentName:"p"},"made by your tutors")," or in case\nyou need to make up for the absence.")),(0,a.kt)("h3",{id:"step-1---starting-from-the-clean-repository"},"Step #1 - Starting from the clean repository"),(0,a.kt)("p",null,"In your repository (either locally or on aisa) type ",(0,a.kt)("inlineCode",{parentName:"p"},"git status")," and check if your\nrepository is clean and you are present on the main branch (",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"main")," or\n",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),"). If you do not know what your default branch is, it is probably ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),"\nand you should not be on any other branch."),(0,a.kt)("p",null,"Output of the command should look like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git status\nOn branch master # Or main or trunk.\nYour branch is up to date with 'origin/master'.\n\nnothing to commit, working tree clean\n")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"In case you are on different branch or there are uncommitted changes,\n",(0,a.kt)("strong",{parentName:"p"},"do not continue!!!")," Clean your repository (commit the changes or discard\nthem), before you continue.")),(0,a.kt)("h3",{id:"step-2---create-new-branch"},"Step #2 - Create new branch"),(0,a.kt)("p",null,"In your repository write command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git checkout -b BRANCH\nSwitched to a new branch 'BRANCH'\n")),(0,a.kt)("p",null,"Instead of ",(0,a.kt)("inlineCode",{parentName:"p"},"BRANCH")," use some reasonable name for the branch. For example if you\nare working on the seminar from 3rd week, name the branch ",(0,a.kt)("inlineCode",{parentName:"p"},"seminar-03"),"."),(0,a.kt)("h3",{id:"step-3---do-the-assignment"},"Step #3 - Do the assignment"),(0,a.kt)("p",null,"Download the skeleton for the seminar assignment, extract and program. For example\nif you are working on 3rd seminar, you can do so by:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ wget https://www.fi.muni.cz/pb071/seminars/seminar-03/pb071-seminar-03.zip\naisa$ unzip pb071-seminar-03.zip\n# Now you should have directory 'seminar-03'.\naisa$ rm pb071-seminar-03.zip\naisa$ cd seminar-03\n# You can work on the assignment.\n")),(0,a.kt)("h3",{id:"step-4---commit-and-upload-the-changes-to-gitlab"},"Step #4 - Commit and upload the changes to GitLab"),(0,a.kt)("p",null,"The same way you ",(0,a.kt)("em",{parentName:"p"},"add")," and ",(0,a.kt)("em",{parentName:"p"},"commit")," files for the homework assignments, you do for\nthe seminar."),(0,a.kt)("p",null,"Now you can upload the changes to GitLab. ",(0,a.kt)("inlineCode",{parentName:"p"},"git push")," is not enough, since repository\non GitLab does not know your new branch. You can solve this by adding arguments:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git push origin BRANCH\n...\nremote: To create a merge request for BRANCH, visit:\nremote: https://gitlab.fi.muni.cz/login/pb071/merge_requests/new?merge_request%5Bsource_branch%5D=BRANCH\n...\n")),(0,a.kt)("p",null,"In the output you should have a link for creating a merge request. If you see this\nlink, open it and skip next step."),(0,a.kt)("h3",{id:"step-5---creating-a-merge-request-manually"},"Step #5 - Creating a merge request manually"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Open your repository on GitLab."),(0,a.kt)("li",{parentName:"ol"},"On the left panel click on ",(0,a.kt)("em",{parentName:"li"},"Merge Requests"),"."),(0,a.kt)("li",{parentName:"ol"},"Click on ",(0,a.kt)("em",{parentName:"li"},"New Merge Request"),"."),(0,a.kt)("li",{parentName:"ol"},"In ",(0,a.kt)("em",{parentName:"li"},"Source branch")," select ",(0,a.kt)("inlineCode",{parentName:"li"},"login/pb071")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"BRANCH"),", which you created."),(0,a.kt)("li",{parentName:"ol"},"In ",(0,a.kt)("em",{parentName:"li"},"Target branch")," select ",(0,a.kt)("inlineCode",{parentName:"li"},"login/pb071")," and your default branch you have seen\nin the output of the first command. (most likely ",(0,a.kt)("inlineCode",{parentName:"li"},"master"),")"),(0,a.kt)("li",{parentName:"ol"},"Click on ",(0,a.kt)("em",{parentName:"li"},"Compare branches and continue"),".")),(0,a.kt)("h3",{id:"step-6---set-assignees"},"Step #6 - Set assignees"),(0,a.kt)("p",null,"On the page that is opened, please check at the top that you are creating merge\nrequest ",(0,a.kt)("strong",{parentName:"p"},"from")," your new branch ",(0,a.kt)("strong",{parentName:"p"},"to")," your default branch (one of ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"main"),"\nor ",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),")."),(0,a.kt)("p",null,"Then in the field ",(0,a.kt)("em",{parentName:"p"},"Assignees")," set your tutors based on the seminar group. You can\nuse login for a quick look up."),(0,a.kt)("p",null,"In the end click on ",(0,a.kt)("em",{parentName:"p"},"Submit merge request"),"."),(0,a.kt)("h3",{id:"step-7---return-to-default-branch"},"Step #7 - Return to default branch"),(0,a.kt)("p",null,"Homework assignments can be submitted only from branches specified in the rules\nfor the course. Because of that, before you do anything else, you should switch\nback to your default branch."),(0,a.kt)("p",null,"First of all, same as in step #1, check that your repository is clean with ",(0,a.kt)("inlineCode",{parentName:"p"},"git status"),".\nFor the sake of safety, do not continue without clean repository. Then with command\n",(0,a.kt)("inlineCode",{parentName:"p"},"git checkout BRANCH")," switch to your default branch ",(0,a.kt)("inlineCode",{parentName:"p"},"BRANCH"),"."),(0,a.kt)("p",null,"If you do not know which branch is your default, try ",(0,a.kt)("inlineCode",{parentName:"p"},"git branch")," that outputs all branches in your repository. Default branch is typically ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", but can\nbe ",(0,a.kt)("inlineCode",{parentName:"p"},"main")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git status\n# Check if repository is clean\n\n# If you know, what is your default branch, you can skip next command.\naisa$ git branch\n# Find the default branch in the list; should be one of the `master`, `main` or\n# `trunk` and you should not have more than one of those.\n# In case the list clears the terminal and you cannot see shell prompt, you can\n# press `q` to quit the pager.\n\naisa$ git checkout master\n")),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Adapted from: ",(0,a.kt)("a",{parentName:"p",href:"https://www.fi.muni.cz/~xlacko1/pb071/mr.html"},"https://www.fi.muni.cz/~xlacko1/pb071/mr.html")))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[7823],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>d});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),p=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),m=p(n),h=a,d=m["".concat(l,".").concat(h)]||m[h]||c[h]||o;return n?r.createElement(d,i(i({ref:t},u),{},{components:n})):r.createElement(d,i({ref:t},u))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=h;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[m]="string"==typeof e?e:a,i[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const o={title:"Submitting merge requests"},i="Submitting merge requests for review",s={unversionedId:"mr",id:"mr",title:"Submitting merge requests",description:"This tutorial aims to show you how to follow basic git workflow and submit changes",source:"@site/pb071/mr.md",sourceDirName:".",slug:"/mr",permalink:"/pb071/mr",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/mr.md",tags:[],version:"current",lastUpdatedAt:1694109587,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{title:"Submitting merge requests"},sidebar:"autogeneratedBar",previous:{title:"Practice exam C",permalink:"/pb071/pexam/cams"}},l={},p=[{value:"Tutorial",id:"tutorial",level:2},{value:"Step #1 - Starting from the clean repository",id:"step-1---starting-from-the-clean-repository",level:3},{value:"Step #2 - Create new branch",id:"step-2---create-new-branch",level:3},{value:"Step #3 - Do the assignment",id:"step-3---do-the-assignment",level:3},{value:"Step #4 - Commit and upload the changes to GitLab",id:"step-4---commit-and-upload-the-changes-to-gitlab",level:3},{value:"Step #5 - Creating a merge request manually",id:"step-5---creating-a-merge-request-manually",level:3},{value:"Step #6 - Set assignees",id:"step-6---set-assignees",level:3},{value:"Step #7 - Return to default branch",id:"step-7---return-to-default-branch",level:3}],u={toc:p},m="wrapper";function c(e){let{components:t,...n}=e;return(0,a.kt)(m,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"submitting-merge-requests-for-review"},"Submitting merge requests for review"),(0,a.kt)("p",null,"This tutorial aims to show you how to follow basic git workflow and submit changes\nthrough ",(0,a.kt)("em",{parentName:"p"},"Merge Requests")," for review."),(0,a.kt)("p",null,"The rudimentary idea behind aims for changes to be present on a separate branch\nthat is supposedly ",(0,a.kt)("em",{parentName:"p"},"merged")," into the default branch. Till then changes can be reviewed\non ",(0,a.kt)("em",{parentName:"p"},"Merge Request")," and additional changes may be made based on the reviews. Once\nthe changes satisfy requirements, the merge request is merged."),(0,a.kt)("h2",{id:"tutorial"},"Tutorial"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Use this tutorial only for bonus assignments ",(0,a.kt)("strong",{parentName:"p"},"made by your tutors")," or in case\nyou need to make up for the absence.")),(0,a.kt)("h3",{id:"step-1---starting-from-the-clean-repository"},"Step #1 - Starting from the clean repository"),(0,a.kt)("p",null,"In your repository (either locally or on aisa) type ",(0,a.kt)("inlineCode",{parentName:"p"},"git status")," and check if your\nrepository is clean and you are present on the main branch (",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"main")," or\n",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),"). If you do not know what your default branch is, it is probably ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),"\nand you should not be on any other branch."),(0,a.kt)("p",null,"Output of the command should look like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git status\nOn branch master # Or main or trunk.\nYour branch is up to date with 'origin/master'.\n\nnothing to commit, working tree clean\n")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"In case you are on different branch or there are uncommitted changes,\n",(0,a.kt)("strong",{parentName:"p"},"do not continue!!!")," Clean your repository (commit the changes or discard\nthem), before you continue.")),(0,a.kt)("h3",{id:"step-2---create-new-branch"},"Step #2 - Create new branch"),(0,a.kt)("p",null,"In your repository write command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git checkout -b BRANCH\nSwitched to a new branch 'BRANCH'\n")),(0,a.kt)("p",null,"Instead of ",(0,a.kt)("inlineCode",{parentName:"p"},"BRANCH")," use some reasonable name for the branch. For example if you\nare working on the seminar from 3rd week, name the branch ",(0,a.kt)("inlineCode",{parentName:"p"},"seminar-03"),"."),(0,a.kt)("h3",{id:"step-3---do-the-assignment"},"Step #3 - Do the assignment"),(0,a.kt)("p",null,"Download the skeleton for the seminar assignment, extract and program. For example\nif you are working on 3rd seminar, you can do so by:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ wget https://www.fi.muni.cz/pb071/seminars/seminar-03/pb071-seminar-03.zip\naisa$ unzip pb071-seminar-03.zip\n# Now you should have directory 'seminar-03'.\naisa$ rm pb071-seminar-03.zip\naisa$ cd seminar-03\n# You can work on the assignment.\n")),(0,a.kt)("h3",{id:"step-4---commit-and-upload-the-changes-to-gitlab"},"Step #4 - Commit and upload the changes to GitLab"),(0,a.kt)("p",null,"The same way you ",(0,a.kt)("em",{parentName:"p"},"add")," and ",(0,a.kt)("em",{parentName:"p"},"commit")," files for the homework assignments, you do for\nthe seminar."),(0,a.kt)("p",null,"Now you can upload the changes to GitLab. ",(0,a.kt)("inlineCode",{parentName:"p"},"git push")," is not enough, since repository\non GitLab does not know your new branch. You can solve this by adding arguments:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git push origin BRANCH\n...\nremote: To create a merge request for BRANCH, visit:\nremote: https://gitlab.fi.muni.cz/login/pb071/merge_requests/new?merge_request%5Bsource_branch%5D=BRANCH\n...\n")),(0,a.kt)("p",null,"In the output you should have a link for creating a merge request. If you see this\nlink, open it and skip next step."),(0,a.kt)("h3",{id:"step-5---creating-a-merge-request-manually"},"Step #5 - Creating a merge request manually"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Open your repository on GitLab."),(0,a.kt)("li",{parentName:"ol"},"On the left panel click on ",(0,a.kt)("em",{parentName:"li"},"Merge Requests"),"."),(0,a.kt)("li",{parentName:"ol"},"Click on ",(0,a.kt)("em",{parentName:"li"},"New Merge Request"),"."),(0,a.kt)("li",{parentName:"ol"},"In ",(0,a.kt)("em",{parentName:"li"},"Source branch")," select ",(0,a.kt)("inlineCode",{parentName:"li"},"login/pb071")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"BRANCH"),", which you created."),(0,a.kt)("li",{parentName:"ol"},"In ",(0,a.kt)("em",{parentName:"li"},"Target branch")," select ",(0,a.kt)("inlineCode",{parentName:"li"},"login/pb071")," and your default branch you have seen\nin the output of the first command. (most likely ",(0,a.kt)("inlineCode",{parentName:"li"},"master"),")"),(0,a.kt)("li",{parentName:"ol"},"Click on ",(0,a.kt)("em",{parentName:"li"},"Compare branches and continue"),".")),(0,a.kt)("h3",{id:"step-6---set-assignees"},"Step #6 - Set assignees"),(0,a.kt)("p",null,"On the page that is opened, please check at the top that you are creating merge\nrequest ",(0,a.kt)("strong",{parentName:"p"},"from")," your new branch ",(0,a.kt)("strong",{parentName:"p"},"to")," your default branch (one of ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"main"),"\nor ",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),")."),(0,a.kt)("p",null,"Then in the field ",(0,a.kt)("em",{parentName:"p"},"Assignees")," set your tutors based on the seminar group. You can\nuse login for a quick look up."),(0,a.kt)("p",null,"In the end click on ",(0,a.kt)("em",{parentName:"p"},"Submit merge request"),"."),(0,a.kt)("h3",{id:"step-7---return-to-default-branch"},"Step #7 - Return to default branch"),(0,a.kt)("p",null,"Homework assignments can be submitted only from branches specified in the rules\nfor the course. Because of that, before you do anything else, you should switch\nback to your default branch."),(0,a.kt)("p",null,"First of all, same as in step #1, check that your repository is clean with ",(0,a.kt)("inlineCode",{parentName:"p"},"git status"),".\nFor the sake of safety, do not continue without clean repository. Then with command\n",(0,a.kt)("inlineCode",{parentName:"p"},"git checkout BRANCH")," switch to your default branch ",(0,a.kt)("inlineCode",{parentName:"p"},"BRANCH"),"."),(0,a.kt)("p",null,"If you do not know which branch is your default, try ",(0,a.kt)("inlineCode",{parentName:"p"},"git branch")," that outputs all branches in your repository. Default branch is typically ",(0,a.kt)("inlineCode",{parentName:"p"},"master"),", but can\nbe ",(0,a.kt)("inlineCode",{parentName:"p"},"main")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"trunk"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"aisa$ git status\n# Check if repository is clean\n\n# If you know, what is your default branch, you can skip next command.\naisa$ git branch\n# Find the default branch in the list; should be one of the `master`, `main` or\n# `trunk` and you should not have more than one of those.\n# In case the list clears the terminal and you cannot see shell prompt, you can\n# press `q` to quit the pager.\n\naisa$ git checkout master\n")),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Adapted from: ",(0,a.kt)("a",{parentName:"p",href:"https://www.fi.muni.cz/~xlacko1/pb071/mr.html"},"https://www.fi.muni.cz/~xlacko1/pb071/mr.html")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f533ef4a.13c50ab8.js b/assets/js/f533ef4a.6e5c0557.js similarity index 99% rename from assets/js/f533ef4a.13c50ab8.js rename to assets/js/f533ef4a.6e5c0557.js index 1cc3c85..a5d850b 100644 --- a/assets/js/f533ef4a.13c50ab8.js +++ b/assets/js/f533ef4a.6e5c0557.js @@ -1 +1 @@ -"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[2160],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,h=u["".concat(s,".").concat(m)]||u[m]||d[m]||i;return n?r.createElement(h,o(o({ref:t},c),{},{components:n})):r.createElement(h,o({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const i={id:"seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n"},o=void 0,l={unversionedId:"bonuses/seminar-05-06",id:"bonuses/seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n",source:"@site/pb071/bonuses/05-06.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-05-06",permalink:"/pb071/bonuses/seminar-05-06",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/05-06.md",tags:[],version:"current",lastUpdatedAt:1694108971,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n"},sidebar:"autogeneratedBar",previous:{title:"4th seminar",permalink:"/pb071/bonuses/seminar-04"},next:{title:"8th seminar",permalink:"/pb071/bonuses/seminar-08"}},s={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Task no. 1: Reverse (0.5 K\u20a1)",id:"task-no-1-reverse-05-k",level:3},{value:"Task no. 2: Vigen\xe8re (0.5 K\u20a1)",id:"task-no-2-vigen\xe8re-05-k",level:3},{value:"Bonus part (0.5 K\u20a1)",id:"bonus-part-05-k",level:4},{value:"Task no. 3: Bit madness (0.5 K\u20a1)",id:"task-no-3-bit-madness-05-k",level:3},{value:"Task no. 4: All combined to BMP (0.5 K\u20a1)",id:"task-no-4-all-combined-to-bmp-05-k",level:3},{value:"Submitting",id:"submitting",level:2}],c={toc:p},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"For this bonus you can get at maximum 2.5 K\u20a1."),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/05-06.tar.gz"},"Source")),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"In this bonus you will implement few functions that will be used together for\nimplementing a very special cipher."),(0,a.kt)("h3",{id:"task-no-1-reverse-05-k"},"Task no. 1: Reverse (0.5 K\u20a1)"),(0,a.kt)("p",null,"Write a function ",(0,a.kt)("inlineCode",{parentName:"p"},"char* reverse(const char* text)")," that returns copy of the input\nstring in reversed order (also uppercase)."),(0,a.kt)("p",null,"In case you are given ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL"),", return ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL"),"."),(0,a.kt)("p",null,"Example (more in tests):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'char* reversed = reverse("Hello world!");\n\nprintf("%s\\n", reversed);\n// "!DLROW OLLEH"\n\nif (reversed != NULL) {\n free(reversed);\n}\n')),(0,a.kt)("h3",{id:"task-no-2-vigen\xe8re-05-k"},"Task no. 2: Vigen\xe8re (0.5 K\u20a1)"),(0,a.kt)("p",null,"Vigen\xe8re cipher is similar to the Caesar cipher, but you also have a key that is\nused for encrypting (or decrypting)."),(0,a.kt)("p",null,"Your task is to write two functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* vigenere_encrypt(const char* key, const char* text)")," for encrypting"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* vigenere_decrypt(const char* key, const char* text)")," for decrypting")),(0,a.kt)("p",null,"In both of those you should return uppercase characters."),(0,a.kt)("p",null,"Meaning of the parameters you are given:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"key")," - String that represents key that is used for ","*","crypting. It consists of\none word and can have only characters of the alphabet. Does not matter if they\nare uppercase or lowercase."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"text")," - String that is to be ","*","crypted.")),(0,a.kt)("p",null,"Function returns address of the encrypted (or decrypted) string. Or ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL")," in case\nerror occurs."),(0,a.kt)("p",null,"Example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'char *encrypted = vigenere_encrypt("CoMPuTeR", "Hello world!");\n\nprintf("%s\\n", encrypted);\n// "JSXAI PSINR!"\n\nif (encrypted != NULL) {\n free(encrypted)\n}\n')),(0,a.kt)("h4",{id:"bonus-part-05-k"},"Bonus part (0.5 K\u20a1)"),(0,a.kt)("p",null,"If you can utilize helper function that would do both encrypting and decrypting,\nyou can gain 0.5 K\u20a1."),(0,a.kt)("p",null,"Usage of ",(0,a.kt)("inlineCode",{parentName:"p"},"true"),"/",(0,a.kt)("inlineCode",{parentName:"p"},"false")," to decide path in code is prohibited. It leads to merging\nof both functions into one. Point of this part is to discover a way to do this\ngenerically in such way that there are no separate paths for one or the other. One\nfunction with no branching for both of them, parametrization is your friend :)"),(0,a.kt)("h3",{id:"task-no-3-bit-madness-05-k"},"Task no. 3: Bit madness (0.5 K\u20a1)"),(0,a.kt)("p",null,"This is a state of the art crypto. Please do not share :)"),(0,a.kt)("p",null,"For encrypting:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Split the character that is to be encrypted in halves (4 and 4 bits each)."),(0,a.kt)("li",{parentName:"ol"},"Bits in 1st half are to be split into pairs. Swap bits in those pairs."),(0,a.kt)("li",{parentName:"ol"},"Then use the 4 bits that you created in the 2nd step for ",(0,a.kt)("inlineCode",{parentName:"li"},"XOR")," with the other\n4 bits.")),(0,a.kt)("p",null,"This simple and ingenious principle will be illustrated on the following example.\nString we want to encrypt is ",(0,a.kt)("inlineCode",{parentName:"p"},"Hello world!"),". We need to encrypt each letter separately,\nso we will demonstrate on letter ",(0,a.kt)("inlineCode",{parentName:"p"},"H"),":"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Letter ",(0,a.kt)("inlineCode",{parentName:"p"},"H")," is represented in ASCII as ",(0,a.kt)("inlineCode",{parentName:"p"},"72"),"."),(0,a.kt)("p",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"p"},"72")," represented in binary is: ",(0,a.kt)("inlineCode",{parentName:"p"},"01001000"),". So first 4 bits are: ",(0,a.kt)("inlineCode",{parentName:"p"},"0100")," and last\n4 bits are ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),".")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"First half of bits (",(0,a.kt)("inlineCode",{parentName:"p"},"0100"),") consists of 2 pairs (",(0,a.kt)("inlineCode",{parentName:"p"},"01")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"00"),") which we swap\n(",(0,a.kt)("inlineCode",{parentName:"p"},"01 ~> 10")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"00 ~> 00"),"). That way we get ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),".")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"That half is used for xor with the other 4 bits:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre"}," 1000 // second half\nXOR 1000 // first half after 2nd step\n--------\n 0000\n"))),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Now we combine both halves (first one is ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),", which we got from the 2nd step\nand second one is ",(0,a.kt)("inlineCode",{parentName:"p"},"0000"),", which we got from the 3rd step) and get ",(0,a.kt)("inlineCode",{parentName:"p"},"10000000"),",\nwhich is encrypted character ",(0,a.kt)("inlineCode",{parentName:"p"},"H")," using this method."))),(0,a.kt)("p",null,"In case of decryption, reverse those steps."),(0,a.kt)("p",null,"Your task is to implement functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"unsigned char* bit_encrypt(const char* text)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* bit_decrypt(const unsigned char* text)"))),(0,a.kt)("p",null,"Example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'unsigned char* encrypted = bit_encrypt("Hello world!");\n\nfor (int i = 0; i < 12;i++) {\n printf("%x ", encrypted[i]);\n //80 9c 95 95 96 11 bc 96 b9 95 9d 10\n}\n\nif (encrypted != NULL) {\n free(encrypted);\n}\n')),(0,a.kt)("h3",{id:"task-no-4-all-combined-to-bmp-05-k"},"Task no. 4: All combined to BMP (0.5 K\u20a1)"),(0,a.kt)("p",null,"Authors of the BMP cipher are non-disclosed :)"),(0,a.kt)("p",null,"Create pair of functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"unsigned char* bmp_encrypt(const char* key, const char* text)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* bmp_decrypt(const char* key, const unsigned char* text)"))),(0,a.kt)("p",null,"BMP cipher consists of following steps for encrypting:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Reverse the input string"),(0,a.kt)("li",{parentName:"ol"},"Use Vigenere on the string you got from step #1"),(0,a.kt)("li",{parentName:"ol"},"Use bit madness on the string you got from step #2")),(0,a.kt)("p",null,"For decrypting, reverse the steps."),(0,a.kt)("h2",{id:"submitting"},"Submitting"),(0,a.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Ideally submit the assignment through the merge request. Step-by-step tutorial is\npresent ",(0,a.kt)("a",{parentName:"p",href:"../mr"},"here"),". For setting assignee my xlogin is ",(0,a.kt)("inlineCode",{parentName:"p"},"xfocko"),"."),(0,a.kt)("p",null,"In case you do not want to experiment on GitLab, send me the source code via email,\nbut please prefix subject with: ",(0,a.kt)("inlineCode",{parentName:"p"},"[PB071/14][seminar-05-06]")),(0,a.kt)("p",null,"Deadline for the submission of the bonus is ",(0,a.kt)("strong",{parentName:"p"},"April 21th 24:00"),"."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkfi=self.webpackChunkfi||[]).push([[2160],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,h=u["".concat(s,".").concat(m)]||u[m]||d[m]||i;return n?r.createElement(h,o(o({ref:t},c),{},{components:n})):r.createElement(h,o({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const i={id:"seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n"},o=void 0,l={unversionedId:"bonuses/seminar-05-06",id:"bonuses/seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n",source:"@site/pb071/bonuses/05-06.md",sourceDirName:"bonuses",slug:"/bonuses/seminar-05-06",permalink:"/pb071/bonuses/seminar-05-06",draft:!1,editUrl:"https://gitlab.com/mfocko/blog/tree/main/pb071/bonuses/05-06.md",tags:[],version:"current",lastUpdatedAt:1694109587,formattedLastUpdatedAt:"Sep 7, 2023",frontMatter:{id:"seminar-05-06",title:"5th and 6th seminar",description:"200IQ encryption.\n"},sidebar:"autogeneratedBar",previous:{title:"4th seminar",permalink:"/pb071/bonuses/seminar-04"},next:{title:"8th seminar",permalink:"/pb071/bonuses/seminar-08"}},s={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Task no. 1: Reverse (0.5 K\u20a1)",id:"task-no-1-reverse-05-k",level:3},{value:"Task no. 2: Vigen\xe8re (0.5 K\u20a1)",id:"task-no-2-vigen\xe8re-05-k",level:3},{value:"Bonus part (0.5 K\u20a1)",id:"bonus-part-05-k",level:4},{value:"Task no. 3: Bit madness (0.5 K\u20a1)",id:"task-no-3-bit-madness-05-k",level:3},{value:"Task no. 4: All combined to BMP (0.5 K\u20a1)",id:"task-no-4-all-combined-to-bmp-05-k",level:3},{value:"Submitting",id:"submitting",level:2}],c={toc:p},u="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"For this bonus you can get at maximum 2.5 K\u20a1."),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"pathname:///files/pb071/bonuses/05-06.tar.gz"},"Source")),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"In this bonus you will implement few functions that will be used together for\nimplementing a very special cipher."),(0,a.kt)("h3",{id:"task-no-1-reverse-05-k"},"Task no. 1: Reverse (0.5 K\u20a1)"),(0,a.kt)("p",null,"Write a function ",(0,a.kt)("inlineCode",{parentName:"p"},"char* reverse(const char* text)")," that returns copy of the input\nstring in reversed order (also uppercase)."),(0,a.kt)("p",null,"In case you are given ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL"),", return ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL"),"."),(0,a.kt)("p",null,"Example (more in tests):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'char* reversed = reverse("Hello world!");\n\nprintf("%s\\n", reversed);\n// "!DLROW OLLEH"\n\nif (reversed != NULL) {\n free(reversed);\n}\n')),(0,a.kt)("h3",{id:"task-no-2-vigen\xe8re-05-k"},"Task no. 2: Vigen\xe8re (0.5 K\u20a1)"),(0,a.kt)("p",null,"Vigen\xe8re cipher is similar to the Caesar cipher, but you also have a key that is\nused for encrypting (or decrypting)."),(0,a.kt)("p",null,"Your task is to write two functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* vigenere_encrypt(const char* key, const char* text)")," for encrypting"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* vigenere_decrypt(const char* key, const char* text)")," for decrypting")),(0,a.kt)("p",null,"In both of those you should return uppercase characters."),(0,a.kt)("p",null,"Meaning of the parameters you are given:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"key")," - String that represents key that is used for ","*","crypting. It consists of\none word and can have only characters of the alphabet. Does not matter if they\nare uppercase or lowercase."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"text")," - String that is to be ","*","crypted.")),(0,a.kt)("p",null,"Function returns address of the encrypted (or decrypted) string. Or ",(0,a.kt)("inlineCode",{parentName:"p"},"NULL")," in case\nerror occurs."),(0,a.kt)("p",null,"Example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'char *encrypted = vigenere_encrypt("CoMPuTeR", "Hello world!");\n\nprintf("%s\\n", encrypted);\n// "JSXAI PSINR!"\n\nif (encrypted != NULL) {\n free(encrypted)\n}\n')),(0,a.kt)("h4",{id:"bonus-part-05-k"},"Bonus part (0.5 K\u20a1)"),(0,a.kt)("p",null,"If you can utilize helper function that would do both encrypting and decrypting,\nyou can gain 0.5 K\u20a1."),(0,a.kt)("p",null,"Usage of ",(0,a.kt)("inlineCode",{parentName:"p"},"true"),"/",(0,a.kt)("inlineCode",{parentName:"p"},"false")," to decide path in code is prohibited. It leads to merging\nof both functions into one. Point of this part is to discover a way to do this\ngenerically in such way that there are no separate paths for one or the other. One\nfunction with no branching for both of them, parametrization is your friend :)"),(0,a.kt)("h3",{id:"task-no-3-bit-madness-05-k"},"Task no. 3: Bit madness (0.5 K\u20a1)"),(0,a.kt)("p",null,"This is a state of the art crypto. Please do not share :)"),(0,a.kt)("p",null,"For encrypting:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Split the character that is to be encrypted in halves (4 and 4 bits each)."),(0,a.kt)("li",{parentName:"ol"},"Bits in 1st half are to be split into pairs. Swap bits in those pairs."),(0,a.kt)("li",{parentName:"ol"},"Then use the 4 bits that you created in the 2nd step for ",(0,a.kt)("inlineCode",{parentName:"li"},"XOR")," with the other\n4 bits.")),(0,a.kt)("p",null,"This simple and ingenious principle will be illustrated on the following example.\nString we want to encrypt is ",(0,a.kt)("inlineCode",{parentName:"p"},"Hello world!"),". We need to encrypt each letter separately,\nso we will demonstrate on letter ",(0,a.kt)("inlineCode",{parentName:"p"},"H"),":"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Letter ",(0,a.kt)("inlineCode",{parentName:"p"},"H")," is represented in ASCII as ",(0,a.kt)("inlineCode",{parentName:"p"},"72"),"."),(0,a.kt)("p",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"p"},"72")," represented in binary is: ",(0,a.kt)("inlineCode",{parentName:"p"},"01001000"),". So first 4 bits are: ",(0,a.kt)("inlineCode",{parentName:"p"},"0100")," and last\n4 bits are ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),".")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"First half of bits (",(0,a.kt)("inlineCode",{parentName:"p"},"0100"),") consists of 2 pairs (",(0,a.kt)("inlineCode",{parentName:"p"},"01")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"00"),") which we swap\n(",(0,a.kt)("inlineCode",{parentName:"p"},"01 ~> 10")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"00 ~> 00"),"). That way we get ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),".")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"That half is used for xor with the other 4 bits:"),(0,a.kt)("pre",{parentName:"li"},(0,a.kt)("code",{parentName:"pre"}," 1000 // second half\nXOR 1000 // first half after 2nd step\n--------\n 0000\n"))),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Now we combine both halves (first one is ",(0,a.kt)("inlineCode",{parentName:"p"},"1000"),", which we got from the 2nd step\nand second one is ",(0,a.kt)("inlineCode",{parentName:"p"},"0000"),", which we got from the 3rd step) and get ",(0,a.kt)("inlineCode",{parentName:"p"},"10000000"),",\nwhich is encrypted character ",(0,a.kt)("inlineCode",{parentName:"p"},"H")," using this method."))),(0,a.kt)("p",null,"In case of decryption, reverse those steps."),(0,a.kt)("p",null,"Your task is to implement functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"unsigned char* bit_encrypt(const char* text)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* bit_decrypt(const unsigned char* text)"))),(0,a.kt)("p",null,"Example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'unsigned char* encrypted = bit_encrypt("Hello world!");\n\nfor (int i = 0; i < 12;i++) {\n printf("%x ", encrypted[i]);\n //80 9c 95 95 96 11 bc 96 b9 95 9d 10\n}\n\nif (encrypted != NULL) {\n free(encrypted);\n}\n')),(0,a.kt)("h3",{id:"task-no-4-all-combined-to-bmp-05-k"},"Task no. 4: All combined to BMP (0.5 K\u20a1)"),(0,a.kt)("p",null,"Authors of the BMP cipher are non-disclosed :)"),(0,a.kt)("p",null,"Create pair of functions:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"unsigned char* bmp_encrypt(const char* key, const char* text)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"char* bmp_decrypt(const char* key, const unsigned char* text)"))),(0,a.kt)("p",null,"BMP cipher consists of following steps for encrypting:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Reverse the input string"),(0,a.kt)("li",{parentName:"ol"},"Use Vigenere on the string you got from step #1"),(0,a.kt)("li",{parentName:"ol"},"Use bit madness on the string you got from step #2")),(0,a.kt)("p",null,"For decrypting, reverse the steps."),(0,a.kt)("h2",{id:"submitting"},"Submitting"),(0,a.kt)("p",null,"In case you have any questions, feel free to reach out to me."),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Ideally submit the assignment through the merge request. Step-by-step tutorial is\npresent ",(0,a.kt)("a",{parentName:"p",href:"../mr"},"here"),". For setting assignee my xlogin is ",(0,a.kt)("inlineCode",{parentName:"p"},"xfocko"),"."),(0,a.kt)("p",null,"In case you do not want to experiment on GitLab, send me the source code via email,\nbut please prefix subject with: ",(0,a.kt)("inlineCode",{parentName:"p"},"[PB071/14][seminar-05-06]")),(0,a.kt)("p",null,"Deadline for the submission of the bonus is ",(0,a.kt)("strong",{parentName:"p"},"April 21th 24:00"),"."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.be793c46.js b/assets/js/runtime~main.05f83fa7.js similarity index 68% rename from assets/js/runtime~main.be793c46.js rename to assets/js/runtime~main.05f83fa7.js index f95901b..6fce875 100644 --- a/assets/js/runtime~main.be793c46.js +++ b/assets/js/runtime~main.05f83fa7.js @@ -1 +1 @@ -(()=>{"use strict";var e,f,a,c,d={},b={};function t(e){var f=b[e];if(void 0!==f)return f.exports;var a=b[e]={exports:{}};return d[e].call(a.exports,a,a.exports,t),a.exports}t.m=d,e=[],t.O=(f,a,c,d)=>{if(!a){var b=1/0;for(i=0;i=d)&&Object.keys(t.O).every((e=>t.O[e](a[o])))?a.splice(o--,1):(r=!1,d0&&e[i-1][2]>d;i--)e[i]=e[i-1];e[i]=[a,c,d]},t.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return t.d(f,{a:f}),f},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,t.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var d=Object.create(null);t.r(d);var b={};f=f||[null,a({}),a([]),a(a)];for(var r=2&c&&e;"object"==typeof r&&!~f.indexOf(r);r=a(r))Object.getOwnPropertyNames(r).forEach((f=>b[f]=()=>e[f]));return b.default=()=>e,t.d(d,b),d},t.d=(e,f)=>{for(var a in f)t.o(f,a)&&!t.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:f[a]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((f,a)=>(t.f[a](e,f),f)),[])),t.u=e=>"assets/js/"+({6:"e25b3183",143:"eb7cc117",146:"dff2ebad",404:"1bebd4ed",516:"a7d8226e",822:"8c0e532b",866:"4200b1a9",932:"4688cd57",1011:"377f3aa1",1050:"a7098721",1171:"d7f7fb17",1235:"86cd1460",1246:"2a09abcd",1272:"b0067e0a",1378:"0220f5fc",1501:"4e286f4e",1505:"3aef4518",1731:"337bc122",1851:"0fcbc6ca",2160:"f533ef4a",2167:"713b7838",2177:"3da4b779",2433:"b5a32f14",2732:"1e298f0c",2741:"d675395f",3039:"765ea78b",3086:"cfa2b263",3089:"a6aa9e1f",3095:"7cf94373",3184:"3de247b5",3223:"834ed470",3340:"58dd4fbd",3388:"29694455",3502:"5af27364",3519:"4621632b",3528:"74c2e0e9",3561:"95b96bb9",3608:"9e4087bc",3618:"a6a48ea2",3731:"51624505",3751:"3720c009",3835:"95be84b6",3906:"1e2009d3",3936:"470a9204",4013:"01a85c17",4064:"f48be158",4195:"c4f5d8e4",4252:"d9adc206",4256:"75cccf44",4269:"0bfe45d5",4287:"75316eff",4477:"94036ea2",4637:"19d7c045",4800:"a2be6ffb",4932:"09bc59e7",4972:"27470891",5126:"d5ca4423",5169:"d79dd549",5383:"8418981c",5388:"fd0b1e16",5430:"52f2a5bf",5521:"9287eafd",5529:"280c26e1",5658:"af8b72a7",5787:"82b3b723",5824:"a80747a0",5975:"4edd2021",6057:"18f481e4",6097:"b0291f37",6103:"ccc49370",6112:"d661cf04",6192:"b2c263ce",6234:"fcc91f97",6498:"be4da062",6554:"8e1fadd0",6890:"22a175ec",7248:"edfd2a45",7509:"9eb50c57",7555:"73d5f13d",7568:"0608d96f",7624:"dadfcff0",7755:"ab2721d4",7780:"d02d148d",7823:"83bf91d3",7883:"4c4e9f30",7918:"17896441",7920:"1a4e3797",7926:"3011a4c0",7963:"4ee12fa2",7979:"37cf4872",8091:"bb882650",8167:"3593220c",8442:"7d580cdb",8480:"8b1802c5",8520:"62d847b3",8610:"6875c492",8643:"ff472cd9",8757:"e89da83e",8769:"90425ffc",8786:"a082abd3",9044:"b9b1ccdc",9157:"788cc978",9193:"2523321d",9197:"b25fbc58",9228:"66d5ef6c",9300:"146d9b84",9385:"95f41f0b",9479:"d74d369f",9514:"1be78505",9611:"f60c832f",9679:"b45dccf0",9710:"52bff962",9814:"c8cbffbd",9817:"14eb3368",9924:"df203c0f"}[e]||e)+"."+{6:"1c50e16b",143:"55f4bd7d",146:"0c0a899d",404:"a838562f",516:"dabdb919",822:"9cbc1be0",866:"e4798bae",932:"4f084bfb",1011:"4c98e03e",1050:"ef506174",1171:"fd985da7",1235:"733128af",1246:"15946a52",1272:"68fd3778",1378:"5b1b8f6e",1426:"d90fc9fa",1501:"b0df1295",1505:"ae37468c",1731:"a2fd825d",1851:"e8ea4c91",2160:"13c50ab8",2167:"e5a05e06",2177:"a33bbff3",2433:"3c491fc9",2732:"caf61e40",2741:"567b4609",3039:"eff9c6dc",3086:"c19c407b",3089:"c08b78c4",3095:"f790d5a8",3184:"66851c3c",3223:"690ec9f0",3340:"f45f89fa",3388:"a2e2c1d7",3502:"400470ed",3519:"f101cb78",3528:"fc48acce",3561:"aefbf3b7",3608:"dadc79bc",3618:"d5faeb42",3731:"ab30cae6",3751:"996e811f",3835:"0463fc28",3906:"7e268ae7",3936:"f961c4a3",4013:"02ca9acb",4064:"eaa96907",4195:"05fc7105",4252:"4d3c59b2",4256:"5b6f1b34",4269:"58ce388b",4287:"a7b24a88",4477:"8be2e014",4637:"18dfd0ba",4800:"f8d1346f",4932:"64a221ae",4972:"d509d6e4",5126:"c7f8ab3b",5169:"ee10504b",5383:"3eb99a51",5388:"7f8a8c44",5430:"f6c9442b",5521:"8885dd15",5529:"27c7a6b1",5658:"1e28998e",5787:"fdccb1de",5824:"4dc03a81",5975:"47ff14e6",6048:"83823b1f",6057:"35406774",6097:"5b91d377",6103:"6c86d4f9",6112:"70911e61",6192:"01869630",6234:"acb581ec",6316:"0ca4149a",6498:"4dfd3eed",6554:"b5230023",6890:"a5706cf0",6945:"04a6ca6a",7248:"1bede75c",7509:"bc586b34",7515:"45da5915",7555:"2c8e245a",7568:"ee46e047",7624:"3cd22a72",7724:"0fff5da7",7755:"e0b371f9",7780:"0cb68506",7823:"21975b05",7883:"f247e2b4",7918:"a160e7e2",7920:"48f1640b",7926:"573f9325",7963:"74d68d7b",7979:"0b06d100",8091:"671a659f",8167:"04c28473",8442:"71718a61",8480:"6f267f4c",8520:"06e10519",8610:"2d487359",8643:"4ff57c91",8757:"a63c019a",8769:"955d8c56",8786:"1797976b",8894:"de4803df",8954:"296edd99",9044:"859f8a18",9157:"4f78c34d",9193:"50613303",9197:"c6b468d1",9228:"fc107ca5",9300:"996dfbcb",9385:"79e14732",9479:"ab677fcf",9487:"b3a824a3",9514:"65bfdbb1",9611:"d6dc7ae0",9679:"5fcb5182",9710:"6e8cadd8",9814:"a55be3a0",9817:"9c4e865a",9924:"1c48be56"}[e]+".js",t.miniCssF=e=>{},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),c={},t.l=(e,f,a,d)=>{if(c[e])c[e].push(f);else{var b,r;if(void 0!==a)for(var o=document.getElementsByTagName("script"),n=0;n{b.onerror=b.onload=null,clearTimeout(l);var d=c[e];if(delete c[e],b.parentNode&&b.parentNode.removeChild(b),d&&d.forEach((e=>e(a))),f)return f(a)},l=setTimeout(u.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=u.bind(null,b.onerror),b.onload=u.bind(null,b.onload),r&&document.head.appendChild(b)}},t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.p="/",t.gca=function(e){return e={17896441:"7918",27470891:"4972",29694455:"3388",51624505:"3731",e25b3183:"6",eb7cc117:"143",dff2ebad:"146","1bebd4ed":"404",a7d8226e:"516","8c0e532b":"822","4200b1a9":"866","4688cd57":"932","377f3aa1":"1011",a7098721:"1050",d7f7fb17:"1171","86cd1460":"1235","2a09abcd":"1246",b0067e0a:"1272","0220f5fc":"1378","4e286f4e":"1501","3aef4518":"1505","337bc122":"1731","0fcbc6ca":"1851",f533ef4a:"2160","713b7838":"2167","3da4b779":"2177",b5a32f14:"2433","1e298f0c":"2732",d675395f:"2741","765ea78b":"3039",cfa2b263:"3086",a6aa9e1f:"3089","7cf94373":"3095","3de247b5":"3184","834ed470":"3223","58dd4fbd":"3340","5af27364":"3502","4621632b":"3519","74c2e0e9":"3528","95b96bb9":"3561","9e4087bc":"3608",a6a48ea2:"3618","3720c009":"3751","95be84b6":"3835","1e2009d3":"3906","470a9204":"3936","01a85c17":"4013",f48be158:"4064",c4f5d8e4:"4195",d9adc206:"4252","75cccf44":"4256","0bfe45d5":"4269","75316eff":"4287","94036ea2":"4477","19d7c045":"4637",a2be6ffb:"4800","09bc59e7":"4932",d5ca4423:"5126",d79dd549:"5169","8418981c":"5383",fd0b1e16:"5388","52f2a5bf":"5430","9287eafd":"5521","280c26e1":"5529",af8b72a7:"5658","82b3b723":"5787",a80747a0:"5824","4edd2021":"5975","18f481e4":"6057",b0291f37:"6097",ccc49370:"6103",d661cf04:"6112",b2c263ce:"6192",fcc91f97:"6234",be4da062:"6498","8e1fadd0":"6554","22a175ec":"6890",edfd2a45:"7248","9eb50c57":"7509","73d5f13d":"7555","0608d96f":"7568",dadfcff0:"7624",ab2721d4:"7755",d02d148d:"7780","83bf91d3":"7823","4c4e9f30":"7883","1a4e3797":"7920","3011a4c0":"7926","4ee12fa2":"7963","37cf4872":"7979",bb882650:"8091","3593220c":"8167","7d580cdb":"8442","8b1802c5":"8480","62d847b3":"8520","6875c492":"8610",ff472cd9:"8643",e89da83e:"8757","90425ffc":"8769",a082abd3:"8786",b9b1ccdc:"9044","788cc978":"9157","2523321d":"9193",b25fbc58:"9197","66d5ef6c":"9228","146d9b84":"9300","95f41f0b":"9385",d74d369f:"9479","1be78505":"9514",f60c832f:"9611",b45dccf0:"9679","52bff962":"9710",c8cbffbd:"9814","14eb3368":"9817",df203c0f:"9924"}[e]||e,t.p+t.u(e)},(()=>{var e={1303:0,532:0};t.f.j=(f,a)=>{var c=t.o(e,f)?e[f]:void 0;if(0!==c)if(c)a.push(c[2]);else if(/^(1303|532)$/.test(f))e[f]=0;else{var d=new Promise(((a,d)=>c=e[f]=[a,d]));a.push(c[2]=d);var b=t.p+t.u(f),r=new Error;t.l(b,(a=>{if(t.o(e,f)&&(0!==(c=e[f])&&(e[f]=void 0),c)){var d=a&&("load"===a.type?"missing":a.type),b=a&&a.target&&a.target.src;r.message="Loading chunk "+f+" failed.\n("+d+": "+b+")",r.name="ChunkLoadError",r.type=d,r.request=b,c[1](r)}}),"chunk-"+f,f)}},t.O.j=f=>0===e[f];var f=(f,a)=>{var c,d,b=a[0],r=a[1],o=a[2],n=0;if(b.some((f=>0!==e[f]))){for(c in r)t.o(r,c)&&(t.m[c]=r[c]);if(o)var i=o(t)}for(f&&f(a);n{"use strict";var e,f,c,a,d={},b={};function t(e){var f=b[e];if(void 0!==f)return f.exports;var c=b[e]={exports:{}};return d[e].call(c.exports,c,c.exports,t),c.exports}t.m=d,e=[],t.O=(f,c,a,d)=>{if(!c){var b=1/0;for(i=0;i=d)&&Object.keys(t.O).every((e=>t.O[e](c[o])))?c.splice(o--,1):(r=!1,d0&&e[i-1][2]>d;i--)e[i]=e[i-1];e[i]=[c,a,d]},t.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return t.d(f,{a:f}),f},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,t.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var d=Object.create(null);t.r(d);var b={};f=f||[null,c({}),c([]),c(c)];for(var r=2&a&&e;"object"==typeof r&&!~f.indexOf(r);r=c(r))Object.getOwnPropertyNames(r).forEach((f=>b[f]=()=>e[f]));return b.default=()=>e,t.d(d,b),d},t.d=(e,f)=>{for(var c in f)t.o(f,c)&&!t.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:f[c]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((f,c)=>(t.f[c](e,f),f)),[])),t.u=e=>"assets/js/"+({6:"e25b3183",143:"eb7cc117",146:"dff2ebad",404:"1bebd4ed",516:"a7d8226e",822:"8c0e532b",866:"4200b1a9",932:"4688cd57",1011:"377f3aa1",1050:"a7098721",1171:"d7f7fb17",1235:"86cd1460",1246:"2a09abcd",1272:"b0067e0a",1378:"0220f5fc",1501:"4e286f4e",1505:"3aef4518",1731:"337bc122",1851:"0fcbc6ca",2160:"f533ef4a",2167:"713b7838",2177:"3da4b779",2433:"b5a32f14",2732:"1e298f0c",2741:"d675395f",3039:"765ea78b",3086:"cfa2b263",3089:"a6aa9e1f",3095:"7cf94373",3184:"3de247b5",3223:"834ed470",3340:"58dd4fbd",3388:"29694455",3502:"5af27364",3519:"4621632b",3528:"74c2e0e9",3561:"95b96bb9",3608:"9e4087bc",3618:"a6a48ea2",3731:"51624505",3751:"3720c009",3835:"95be84b6",3906:"1e2009d3",3936:"470a9204",4013:"01a85c17",4064:"f48be158",4195:"c4f5d8e4",4252:"d9adc206",4256:"75cccf44",4269:"0bfe45d5",4287:"75316eff",4477:"94036ea2",4637:"19d7c045",4800:"a2be6ffb",4932:"09bc59e7",4972:"27470891",5126:"d5ca4423",5169:"d79dd549",5383:"8418981c",5388:"fd0b1e16",5430:"52f2a5bf",5521:"9287eafd",5529:"280c26e1",5658:"af8b72a7",5787:"82b3b723",5824:"a80747a0",5975:"4edd2021",6057:"18f481e4",6097:"b0291f37",6103:"ccc49370",6112:"d661cf04",6192:"b2c263ce",6234:"fcc91f97",6498:"be4da062",6554:"8e1fadd0",6890:"22a175ec",7248:"edfd2a45",7509:"9eb50c57",7555:"73d5f13d",7568:"0608d96f",7624:"dadfcff0",7755:"ab2721d4",7780:"d02d148d",7823:"83bf91d3",7883:"4c4e9f30",7918:"17896441",7920:"1a4e3797",7926:"3011a4c0",7963:"4ee12fa2",7979:"37cf4872",8091:"bb882650",8167:"3593220c",8442:"7d580cdb",8480:"8b1802c5",8520:"62d847b3",8610:"6875c492",8643:"ff472cd9",8757:"e89da83e",8769:"90425ffc",8786:"a082abd3",9044:"b9b1ccdc",9157:"788cc978",9193:"2523321d",9197:"b25fbc58",9228:"66d5ef6c",9300:"146d9b84",9385:"95f41f0b",9479:"d74d369f",9514:"1be78505",9611:"f60c832f",9679:"b45dccf0",9710:"52bff962",9814:"c8cbffbd",9817:"14eb3368",9924:"df203c0f"}[e]||e)+"."+{6:"1c50e16b",143:"55f4bd7d",146:"0c0a899d",404:"a838562f",516:"dabdb919",822:"9cbc1be0",866:"e4798bae",932:"4f084bfb",1011:"4c98e03e",1050:"ef506174",1171:"fd985da7",1235:"733128af",1246:"15946a52",1272:"68fd3778",1378:"5b1b8f6e",1426:"d90fc9fa",1501:"b0df1295",1505:"ae37468c",1731:"22826266",1851:"e8ea4c91",2160:"6e5c0557",2167:"e5a05e06",2177:"a33bbff3",2433:"3c491fc9",2732:"caf61e40",2741:"567b4609",3039:"eff9c6dc",3086:"c19c407b",3089:"c08b78c4",3095:"f6d9052f",3184:"66851c3c",3223:"668efafa",3340:"f45f89fa",3388:"a2e2c1d7",3502:"400470ed",3519:"f101cb78",3528:"fc48acce",3561:"aefbf3b7",3608:"dadc79bc",3618:"d5faeb42",3731:"ab30cae6",3751:"996e811f",3835:"0463fc28",3906:"7e268ae7",3936:"f961c4a3",4013:"02ca9acb",4064:"eaa96907",4195:"05fc7105",4252:"4d3c59b2",4256:"5b6f1b34",4269:"58ce388b",4287:"a7b24a88",4477:"8be2e014",4637:"18dfd0ba",4800:"f8d1346f",4932:"64a221ae",4972:"d509d6e4",5126:"c7f8ab3b",5169:"ee10504b",5383:"3eb99a51",5388:"7f8a8c44",5430:"f6c9442b",5521:"8885dd15",5529:"27c7a6b1",5658:"1e28998e",5787:"fdccb1de",5824:"4dc03a81",5975:"47ff14e6",6048:"83823b1f",6057:"35406774",6097:"5b91d377",6103:"6c86d4f9",6112:"70911e61",6192:"01869630",6234:"acb581ec",6316:"0ca4149a",6498:"4dfd3eed",6554:"b5230023",6890:"a5706cf0",6945:"04a6ca6a",7248:"1bede75c",7509:"bc586b34",7515:"45da5915",7555:"2c8e245a",7568:"ee46e047",7624:"3cd22a72",7724:"0fff5da7",7755:"e0b371f9",7780:"0cb68506",7823:"193b1d35",7883:"f247e2b4",7918:"a160e7e2",7920:"48f1640b",7926:"573f9325",7963:"bd3f9667",7979:"0b06d100",8091:"671a659f",8167:"04c28473",8442:"bd936269",8480:"6f267f4c",8520:"06e10519",8610:"2d487359",8643:"4ff57c91",8757:"a63c019a",8769:"955d8c56",8786:"1797976b",8894:"de4803df",8954:"296edd99",9044:"859f8a18",9157:"4f78c34d",9193:"54e7755c",9197:"c6b468d1",9228:"fc107ca5",9300:"996dfbcb",9385:"79e14732",9479:"ab677fcf",9487:"b3a824a3",9514:"65bfdbb1",9611:"d6dc7ae0",9679:"5fcb5182",9710:"6e8cadd8",9814:"a55be3a0",9817:"9c4e865a",9924:"1c48be56"}[e]+".js",t.miniCssF=e=>{},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),a={},t.l=(e,f,c,d)=>{if(a[e])a[e].push(f);else{var b,r;if(void 0!==c)for(var o=document.getElementsByTagName("script"),n=0;n{b.onerror=b.onload=null,clearTimeout(l);var d=a[e];if(delete a[e],b.parentNode&&b.parentNode.removeChild(b),d&&d.forEach((e=>e(c))),f)return f(c)},l=setTimeout(u.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=u.bind(null,b.onerror),b.onload=u.bind(null,b.onload),r&&document.head.appendChild(b)}},t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.p="/",t.gca=function(e){return e={17896441:"7918",27470891:"4972",29694455:"3388",51624505:"3731",e25b3183:"6",eb7cc117:"143",dff2ebad:"146","1bebd4ed":"404",a7d8226e:"516","8c0e532b":"822","4200b1a9":"866","4688cd57":"932","377f3aa1":"1011",a7098721:"1050",d7f7fb17:"1171","86cd1460":"1235","2a09abcd":"1246",b0067e0a:"1272","0220f5fc":"1378","4e286f4e":"1501","3aef4518":"1505","337bc122":"1731","0fcbc6ca":"1851",f533ef4a:"2160","713b7838":"2167","3da4b779":"2177",b5a32f14:"2433","1e298f0c":"2732",d675395f:"2741","765ea78b":"3039",cfa2b263:"3086",a6aa9e1f:"3089","7cf94373":"3095","3de247b5":"3184","834ed470":"3223","58dd4fbd":"3340","5af27364":"3502","4621632b":"3519","74c2e0e9":"3528","95b96bb9":"3561","9e4087bc":"3608",a6a48ea2:"3618","3720c009":"3751","95be84b6":"3835","1e2009d3":"3906","470a9204":"3936","01a85c17":"4013",f48be158:"4064",c4f5d8e4:"4195",d9adc206:"4252","75cccf44":"4256","0bfe45d5":"4269","75316eff":"4287","94036ea2":"4477","19d7c045":"4637",a2be6ffb:"4800","09bc59e7":"4932",d5ca4423:"5126",d79dd549:"5169","8418981c":"5383",fd0b1e16:"5388","52f2a5bf":"5430","9287eafd":"5521","280c26e1":"5529",af8b72a7:"5658","82b3b723":"5787",a80747a0:"5824","4edd2021":"5975","18f481e4":"6057",b0291f37:"6097",ccc49370:"6103",d661cf04:"6112",b2c263ce:"6192",fcc91f97:"6234",be4da062:"6498","8e1fadd0":"6554","22a175ec":"6890",edfd2a45:"7248","9eb50c57":"7509","73d5f13d":"7555","0608d96f":"7568",dadfcff0:"7624",ab2721d4:"7755",d02d148d:"7780","83bf91d3":"7823","4c4e9f30":"7883","1a4e3797":"7920","3011a4c0":"7926","4ee12fa2":"7963","37cf4872":"7979",bb882650:"8091","3593220c":"8167","7d580cdb":"8442","8b1802c5":"8480","62d847b3":"8520","6875c492":"8610",ff472cd9:"8643",e89da83e:"8757","90425ffc":"8769",a082abd3:"8786",b9b1ccdc:"9044","788cc978":"9157","2523321d":"9193",b25fbc58:"9197","66d5ef6c":"9228","146d9b84":"9300","95f41f0b":"9385",d74d369f:"9479","1be78505":"9514",f60c832f:"9611",b45dccf0:"9679","52bff962":"9710",c8cbffbd:"9814","14eb3368":"9817",df203c0f:"9924"}[e]||e,t.p+t.u(e)},(()=>{var e={1303:0,532:0};t.f.j=(f,c)=>{var a=t.o(e,f)?e[f]:void 0;if(0!==a)if(a)c.push(a[2]);else if(/^(1303|532)$/.test(f))e[f]=0;else{var d=new Promise(((c,d)=>a=e[f]=[c,d]));c.push(a[2]=d);var b=t.p+t.u(f),r=new Error;t.l(b,(c=>{if(t.o(e,f)&&(0!==(a=e[f])&&(e[f]=void 0),a)){var d=c&&("load"===c.type?"missing":c.type),b=c&&c.target&&c.target.src;r.message="Loading chunk "+f+" failed.\n("+d+": "+b+")",r.name="ChunkLoadError",r.type=d,r.request=b,a[1](r)}}),"chunk-"+f,f)}},t.O.j=f=>0===e[f];var f=(f,c)=>{var a,d,b=c[0],r=c[1],o=c[2],n=0;if(b.some((f=>0!==e[f]))){for(a in r)t.o(r,a)&&(t.m[a]=r[a]);if(o)var i=o(t)}for(f&&f(c);n - + @@ -61,7 +61,7 @@ proceeded with the upgrade.


  1. vpsFree.cz
  2. Even though I've been running archLinux on some Raspberry Pi's and also on one of my “home servers”, before getting the VPS. You could say I like to live on the edge…
- + \ No newline at end of file diff --git a/blog/aoc-2022/1st-week/index.html b/blog/aoc-2022/1st-week/index.html index d0562bf..690b771 100644 --- a/blog/aoc-2022/1st-week/index.html +++ b/blog/aoc-2022/1st-week/index.html @@ -13,7 +13,7 @@ - + @@ -105,7 +105,7 @@ only one “owner” of a mutable reference at a time (and dynamically, as oppos to the Cell<T>).

Therefore to be precise and correct about the equivalents of std::shared_ptr<T> in Rust, we can say that

  • Rc<T> is an equivalent of a const std::shared_ptr<T>,
  • and Rc<RefCell<T>> is an equivalent of a std::shared_ptr<T>.

You can easily see that they only differ in the mutability. (And even that is not as simple as it seems, because there is also Cell<T>)

- + \ No newline at end of file diff --git a/blog/aoc-2022/2nd-week/index.html b/blog/aoc-2022/2nd-week/index.html index 30811dd..bc51503 100644 --- a/blog/aoc-2022/2nd-week/index.html +++ b/blog/aoc-2022/2nd-week/index.html @@ -13,7 +13,7 @@ - + @@ -166,7 +166,7 @@ copy-paste, cause the cost of this “monstrosity” outweighs the benefits of n types, you'll get suggested certain changes by the clippy. For example if you consider the following piece of code

fn get_sum(nums: &Vec<i32>) -> i32 {
nums.iter().sum()
}

fn main() {
let nums = vec![1, 2, 3];
println!("Sum: {}", get_sum(&nums));
}

and you run clippy on it, you will get

Checking playground v0.0.1 (/playground)
warning: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
--> src/main.rs:1:18
|
1 | fn get_sum(nums: &Vec<i32>) -> i32 {
| ^^^^^^^^^ help: change this to: `&[i32]`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
= note: `#[warn(clippy::ptr_arg)]` on by default

warning: `playground` (bin "playground") generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 0.61s

However, if you introduce a type alias, such as

type Numbers = Vec<i32>;

Then clippy won't say anything, cause there is literally nothing to suggest. However the outcome is not the same…

- + \ No newline at end of file diff --git a/blog/aoc-2022/3rd-week/index.html b/blog/aoc-2022/3rd-week/index.html index dd9c8ec..b23945d 100644 --- a/blog/aoc-2022/3rd-week/index.html +++ b/blog/aoc-2022/3rd-week/index.html @@ -13,7 +13,7 @@ - + @@ -106,7 +106,7 @@ do2Neg trait3. I was dealing with a binary tree and needed a way how to look at the other side, so I have just implemented the negation for flipping between left and right 😄


  1. Default docs
  2. Pardon my example from the graph algorithms ;)
  3. Neg docs
- + \ No newline at end of file diff --git a/blog/aoc-2022/4th-week/index.html b/blog/aoc-2022/4th-week/index.html index 520111b..c8c71c3 100644 --- a/blog/aoc-2022/4th-week/index.html +++ b/blog/aoc-2022/4th-week/index.html @@ -13,7 +13,7 @@ - + @@ -130,7 +130,7 @@ implementation is also very helpful in a lot of cases, e.g. debugging output, copying, equality comparison, etc.

I confess to touching more “cursed” parts of the Rust, such as macros to declutter the copy-paste for tests or writing my own structures that need to carry a lifetime for their own fields.

tl;dr Relatively pleasant language until you hit brick wall 😉


See you next year! Maybe in Rust, maybe not 🙃

- + \ No newline at end of file diff --git a/blog/aoc-2022/intro/index.html b/blog/aoc-2022/intro/index.html index 8963ab4..449ead5 100644 --- a/blog/aoc-2022/intro/index.html +++ b/blog/aoc-2022/intro/index.html @@ -13,7 +13,7 @@ - + @@ -85,7 +85,7 @@ can be installed only once and therefore it can fail, that is how we got the ::install which unwraps the »result« of the installation.

Overall we will get to a template like this:

use aoc_2022::*;

use color_eyre::eyre::Result;
use tracing::info;
use tracing_subscriber::EnvFilter;

type Input = String;
type Output = i32;

fn parse_input(path: &str) -> Input {
todo!()
}

fn part1(input: &Input) -> Output {
todo!()
}

fn part2(input: &Input) -> Output {
todo!()
}

fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.with_target(false)
.with_file(true)
.with_line_number(true)
.without_time()
.compact()
.init();
color_eyre::install()?;

let input = parse_input("inputs/dayXX.txt");

info!("Part 1: {}", part_1(&input));
info!("Part 2: {}", part_2(&input));

Ok(())
}

  1. Copy-pasting might be a relaxing thing to do, but you can also discover nasty stuff about your PC. See this Reddit post and the comment.
  2. GitHub profile
  3. Even though you can use it even for libraries, but handling errors from libraries using anyhow is nasty… You will be the stinky one ;)
- + \ No newline at end of file diff --git a/blog/archive/index.html b/blog/archive/index.html index 066479b..f4a81b5 100644 --- a/blog/archive/index.html +++ b/blog/archive/index.html @@ -13,13 +13,13 @@ - + - + \ No newline at end of file diff --git a/blog/index.html b/blog/index.html index c891b3c..45ff5ff 100644 --- a/blog/index.html +++ b/blog/index.html @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@
- + \ No newline at end of file diff --git a/blog/leetcode/sort-diagonally/index.html b/blog/leetcode/sort-diagonally/index.html index 524fb4b..d1e8b9c 100644 --- a/blog/leetcode/sort-diagonally/index.html +++ b/blog/leetcode/sort-diagonally/index.html @@ -13,7 +13,7 @@ - + @@ -107,7 +107,7 @@ remaining requirements of the random access iterator. Let's see wh get yelled at by a compiler for the following reasons:

/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1792:11: error: object of type 'diagonal<int>::diagonal_iter' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]
__last = __next;
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1817:11: note: in instantiation of function template specialization 'std::__unguarded_linear_insert<diagonal<int>::diagonal_iter, __gnu_cxx::__ops::_Val_less_iter>' requested here
std::__unguarded_linear_insert(__i,
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1849:9: note: in instantiation of function template specialization 'std::__insertion_sort<diagonal<int>::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here
std::__insertion_sort(__first, __first + int(_S_threshold), __comp);
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1940:9: note: in instantiation of function template specialization 'std::__final_insertion_sort<diagonal<int>::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here
std::__final_insertion_sort(__first, __last, __comp);
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization 'std::__sort<diagonal<int>::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here
std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());
^
matrix-sort.cpp:161:18: note: in instantiation of function template specialization 'std::sort<diagonal<int>::diagonal_iter>' requested here
std::sort(d.begin(), d.end());
^
matrix-sort.cpp:17:19: note: copy assignment operator of 'diagonal_iter' is implicitly deleted because field 'm' is of reference type 'diagonal<int>::matrix_t &' (aka 'vector<std::vector<int>> &')
matrix_t& m;
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1830:2: error: no matching function for call to '__unguarded_linear_insert' [clang-diagnostic-error]
std::__unguarded_linear_insert(__i,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1850:9: note: in instantiation of function template specialization 'std::__unguarded_insertion_sort<diagonal<int>::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here
std::__unguarded_insertion_sort(__first + int(_S_threshold), __last,
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1940:9: note: in instantiation of function template specialization 'std::__final_insertion_sort<diagonal<int>::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here
std::__final_insertion_sort(__first, __last, __comp);
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization 'std::__sort<diagonal<int>::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here
std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());
^
matrix-sort.cpp:161:18: note: in instantiation of function template specialization 'std::sort<diagonal<int>::diagonal_iter>' requested here
std::sort(d.begin(), d.end());
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1782:5: note: candidate template ignored: substitution failure [with _RandomAccessIterator = diagonal<int>::diagonal_iter, _Compare = __gnu_cxx::__ops::_Val_less_iter]
__unguarded_linear_insert(_RandomAccessIterator __last,
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1923:11: error: object of type 'diagonal<int>::diagonal_iter' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]
__last = __cut;
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1937:9: note: in instantiation of function template specialization 'std::__introsort_loop<diagonal<int>::diagonal_iter, long, __gnu_cxx::__ops::_Iter_less_iter>' requested here
std::__introsort_loop(__first, __last,
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:4820:12: note: in instantiation of function template specialization 'std::__sort<diagonal<int>::diagonal_iter, __gnu_cxx::__ops::_Iter_less_iter>' requested here
std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter());
^
matrix-sort.cpp:161:18: note: in instantiation of function template specialization 'std::sort<diagonal<int>::diagonal_iter>' requested here
std::sort(d.begin(), d.end());
^
matrix-sort.cpp:17:19: note: copy assignment operator of 'diagonal_iter' is implicitly deleted because field 'm' is of reference type 'diagonal<int>::matrix_t &' (aka 'vector<std::vector<int>> &')
matrix_t& m;
^

That's a lot of noise, isn't it? Let's focus on the important parts:

/usr/bin/../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/bits/stl_algo.h:1792:11: error: object of type 'diagonal<int>::diagonal_iter' cannot be assigned because its copy assignment operator is implicitly deleted [clang-diagnostic-error]

matrix-sort.cpp:17:19: note: copy assignment operator of 'diagonal_iter' is implicitly deleted because field 'm' is of reference type 'diagonal<int>::matrix_t &' (aka 'vector<std::vector<int>> &')
matrix_t& m;
^

Ah! We have a reference in our iterator, and this prevents us from having a copy assignment operator (that is used “somewhere” in the sorting algorithm). Well… Let's just wrap it!

# we need to keep a different type than reference
- matrix_t& m;
+ std::reference_wrapper<matrix_t> m;

# in comparison we need to get the reference out of the wrapper first
- return x == rhs.x && y == rhs.y && m == rhs.m;
+ return x == rhs.x && y == rhs.y && m.get() == rhs.m.get();

# same when we return a reference to the “cell” in the matrix
- reference operator*() const { return m[y][x]; }
+ reference operator*() const { return m.get()[y][x]; }

# and finally in the assertions that we set for the “distance” and “less than”
- assert(m == rhs.m);
+ assert(m.get() == rhs.m.get());

We're done now! We have written an iterator over diagonals for a 2D vector. You can have a look at the final result here.


  1. just because I'm used to it and don't care about your opinion ;)
  2. exercise at your own risk
  3. me in 5 minutes in fact, but don't make me scared
  4. me in the next section…
- + \ No newline at end of file diff --git a/blog/tags/admin/index.html b/blog/tags/admin/index.html index 7e56e26..85b09d1 100644 --- a/blog/tags/admin/index.html +++ b/blog/tags/admin/index.html @@ -13,14 +13,14 @@ - + - + \ No newline at end of file diff --git a/blog/tags/advent-of-code-2022/index.html b/blog/tags/advent-of-code-2022/index.html index d5cdae2..45b6868 100644 --- a/blog/tags/advent-of-code-2022/index.html +++ b/blog/tags/advent-of-code-2022/index.html @@ -13,13 +13,13 @@ - +

5 posts tagged with "advent-of-code-2022"

View All Tags
- + \ No newline at end of file diff --git a/blog/tags/advent-of-code/index.html b/blog/tags/advent-of-code/index.html index 208449c..9f8a276 100644 --- a/blog/tags/advent-of-code/index.html +++ b/blog/tags/advent-of-code/index.html @@ -13,13 +13,13 @@ - +

5 posts tagged with "advent-of-code"

View All Tags
- + \ No newline at end of file diff --git a/blog/tags/copr/index.html b/blog/tags/copr/index.html index 3a160b1..cb528bd 100644 --- a/blog/tags/copr/index.html +++ b/blog/tags/copr/index.html @@ -13,14 +13,14 @@ - + - + \ No newline at end of file diff --git a/blog/tags/cpp/index.html b/blog/tags/cpp/index.html index 7776db8..5c6a2d1 100644 --- a/blog/tags/cpp/index.html +++ b/blog/tags/cpp/index.html @@ -13,14 +13,14 @@ - + - + \ No newline at end of file diff --git a/blog/tags/index.html b/blog/tags/index.html index 4a82b73..38975f0 100644 --- a/blog/tags/index.html +++ b/blog/tags/index.html @@ -13,13 +13,13 @@ - + - + \ No newline at end of file diff --git a/blog/tags/iterators/index.html b/blog/tags/iterators/index.html index 400c077..3e80f08 100644 --- a/blog/tags/iterators/index.html +++ b/blog/tags/iterators/index.html @@ -13,14 +13,14 @@ - + - + \ No newline at end of file diff --git a/blog/tags/leetcode/index.html b/blog/tags/leetcode/index.html index 12ef649..115556b 100644 --- a/blog/tags/leetcode/index.html +++ b/blog/tags/leetcode/index.html @@ -13,14 +13,14 @@ - + - + \ No newline at end of file diff --git a/blog/tags/red-hat/index.html b/blog/tags/red-hat/index.html index 778decd..b395c6d 100644 --- a/blog/tags/red-hat/index.html +++ b/blog/tags/red-hat/index.html @@ -13,14 +13,14 @@ - + - + \ No newline at end of file diff --git a/blog/tags/rust/index.html b/blog/tags/rust/index.html index 586fc4e..2434aa4 100644 --- a/blog/tags/rust/index.html +++ b/blog/tags/rust/index.html @@ -13,13 +13,13 @@ - +

5 posts tagged with "rust"

View All Tags
- + \ No newline at end of file diff --git a/blog/tags/vps/index.html b/blog/tags/vps/index.html index 54bb7df..d4d1d85 100644 --- a/blog/tags/vps/index.html +++ b/blog/tags/vps/index.html @@ -13,14 +13,14 @@ - + - + \ No newline at end of file diff --git a/blog/tags/🏭/index.html b/blog/tags/🏭/index.html index 0162360..09f8c0d 100644 --- a/blog/tags/🏭/index.html +++ b/blog/tags/🏭/index.html @@ -13,14 +13,14 @@ - + - + \ No newline at end of file diff --git a/contributions/index.html b/contributions/index.html index 276a3df..421c0eb 100644 --- a/contributions/index.html +++ b/contributions/index.html @@ -13,13 +13,13 @@ - +

Contributions

Many of my contributions to open-source projects.

Fedora Infrastructure Ansible

Description

Collection of Ansible playbooks that powers the Fedora Infrastructure.

Contribution

I have adjusted the groups in the Bodhi playbooks after Packit has been granted the privileges to propose updates without restrictions.

Bodhi

Description

Bodhi is a web-system that facilitates the process of publishing updates for a Fedora-based software distribution.

Contribution

I have adjusted the client, so that it doesn't show secrets in terminal when you log in to the Bodhi via browser.

Gluetool Modules Collection

Description

Modules for gluetool — a command line centric framework usable for glueing modules into a pipeline.

Contribution
  • I have proposed a possible implementation of git merging that was later on extended.
  • I have tried to help out with Copr module after they deprecated older version of their API.

Pagure

Description

Pagure is a git-centered forge, python based using pygit2.

Contribution

I have added an API endpoint for reopening pull requests.

Copr

Description

RPM build system - upstream for Copr.

Contribution
  • Supporting external repositories for custom SRPM build method.
  • Allowing admins of Copr repositories to build without the need to ask for explicit builder permissions.

python-gitlab

Description

A python wrapper for the GitLab API.

Contribution

I have contributed support for the merge_ref on merge requests that hasn't been supported, yet it was present in the GitLab API.

PatternFly React

Description

A set of React components for the PatternFly project.

Contribution

When working on Packit Dashboard, I have spotted smaller bugs that were present in this project and fixed them upstream to provide better experience for our users.

Fira Code

Description

Free monospaced font with programming ligatures.

Contribution

I have set up a GitHub Action for building the font on each push to the default branch allowing users to install bleeding edge version of the font.

nixpkgs

Description

Nixpkgs is a collection of over 80,000 software packages that can be installed with the Nix package manager. It also implements NixOS, a purely-functional Linux distribution.

Contribution

When I was trying out the nixpkgs, I have tried to bump .NET Core to the latest version. My changes haven't been accepted as they required bumping of multiple more packages that depended upon the .NET Core.

Darcula

Description

A theme for Visual Studio Code based on Darcula theme from Jetbrains IDEs.

Contribution

I have contributed support for diff files, though the project doesn't seem to be live anymore, so it hasn't been accepted as of now.

Packit

Description

An open source project aiming to ease the integration of your project with Fedora Linux, CentOS Stream and other distributions.

Contribution

Have a look at my pull requests.

Snitch

Description

Language agnostic tool that collects TODOs in the source code and reports them as Issues.

Contribution
  • Environment variable support for self-hosted GitLab instances
  • GitLab support

Karel the Robot

Description

Karel the robot is in general an educational programming language for beginners, created by Richard E. Pattis. This is implementation of Karel the Robot for C programming language.

This project is used for educational purposes at TUKE.

Contribution

I have contributed some refactoring tips to the author of the library.

- + \ No newline at end of file diff --git a/files/ib002/graphs/iterative-and-iterators.tar.bz2 b/files/ib002/graphs/iterative-and-iterators.tar.bz2 new file mode 100644 index 0000000..a1c4ca6 Binary files /dev/null and b/files/ib002/graphs/iterative-and-iterators.tar.bz2 differ diff --git a/files/ib002/graphs/iterative-and-iterators.tar.gz b/files/ib002/graphs/iterative-and-iterators.tar.gz new file mode 100644 index 0000000..fdd0fad Binary files /dev/null and b/files/ib002/graphs/iterative-and-iterators.tar.gz differ diff --git a/files/ib002/recursion/karel-1.tar.bz2 b/files/ib002/recursion/karel-1.tar.bz2 new file mode 100644 index 0000000..7ac31ec Binary files /dev/null and b/files/ib002/recursion/karel-1.tar.bz2 differ diff --git a/files/ib002/recursion/karel-1.tar.gz b/files/ib002/recursion/karel-1.tar.gz new file mode 100644 index 0000000..d98f3c6 Binary files /dev/null and b/files/ib002/recursion/karel-1.tar.gz differ diff --git a/files/ib002/recursion/pyramid-slide-down.tar.bz2 b/files/ib002/recursion/pyramid-slide-down.tar.bz2 new file mode 100644 index 0000000..2ed1eed Binary files /dev/null and b/files/ib002/recursion/pyramid-slide-down.tar.bz2 differ diff --git a/files/ib002/recursion/pyramid-slide-down.tar.gz b/files/ib002/recursion/pyramid-slide-down.tar.gz new file mode 100644 index 0000000..86a968e Binary files /dev/null and b/files/ib002/recursion/pyramid-slide-down.tar.gz differ diff --git a/files/ib002/time-complexity/extend.tar.bz2 b/files/ib002/time-complexity/extend.tar.bz2 new file mode 100644 index 0000000..71f6910 Binary files /dev/null and b/files/ib002/time-complexity/extend.tar.bz2 differ diff --git a/files/ib002/time-complexity/extend.tar.gz b/files/ib002/time-complexity/extend.tar.gz new file mode 100644 index 0000000..253fa3c Binary files /dev/null and b/files/ib002/time-complexity/extend.tar.gz differ diff --git a/files/pb071/bonuses/03.tar.bz2 b/files/pb071/bonuses/03.tar.bz2 index 5243e79..d490b2e 100644 Binary files a/files/pb071/bonuses/03.tar.bz2 and b/files/pb071/bonuses/03.tar.bz2 differ diff --git a/files/pb071/bonuses/03.tar.gz b/files/pb071/bonuses/03.tar.gz index 79580cf..3669000 100644 Binary files a/files/pb071/bonuses/03.tar.gz and b/files/pb071/bonuses/03.tar.gz differ diff --git a/files/pb071/bonuses/04.tar.bz2 b/files/pb071/bonuses/04.tar.bz2 index f54dcc8..9a3ad9b 100644 Binary files a/files/pb071/bonuses/04.tar.bz2 and b/files/pb071/bonuses/04.tar.bz2 differ diff --git a/files/pb071/bonuses/04.tar.gz b/files/pb071/bonuses/04.tar.gz index 5f597fa..3364059 100644 Binary files a/files/pb071/bonuses/04.tar.gz and b/files/pb071/bonuses/04.tar.gz differ diff --git a/files/pb071/bonuses/05-06.tar.bz2 b/files/pb071/bonuses/05-06.tar.bz2 index d716213..3dd58f3 100644 Binary files a/files/pb071/bonuses/05-06.tar.bz2 and b/files/pb071/bonuses/05-06.tar.bz2 differ diff --git a/files/pb071/bonuses/05-06.tar.gz b/files/pb071/bonuses/05-06.tar.gz index 87b5c56..02c9c76 100644 Binary files a/files/pb071/bonuses/05-06.tar.gz and b/files/pb071/bonuses/05-06.tar.gz differ diff --git a/files/pb071/bonuses/08.tar.bz2 b/files/pb071/bonuses/08.tar.bz2 index 0d0eb4e..227963d 100644 Binary files a/files/pb071/bonuses/08.tar.bz2 and b/files/pb071/bonuses/08.tar.bz2 differ diff --git a/files/pb071/bonuses/08.tar.gz b/files/pb071/bonuses/08.tar.gz index 7a9db27..bb725d6 100644 Binary files a/files/pb071/bonuses/08.tar.gz and b/files/pb071/bonuses/08.tar.gz differ diff --git a/files/pb071/bonuses/10.tar.bz2 b/files/pb071/bonuses/10.tar.bz2 index 02fa170..b89f899 100644 Binary files a/files/pb071/bonuses/10.tar.bz2 and b/files/pb071/bonuses/10.tar.bz2 differ diff --git a/files/pb071/bonuses/10.tar.gz b/files/pb071/bonuses/10.tar.gz index ceba562..0607344 100644 Binary files a/files/pb071/bonuses/10.tar.gz and b/files/pb071/bonuses/10.tar.gz differ diff --git a/ib002/algorithms-correctness/postcondition-ambiguity/index.html b/ib002/algorithms-correctness/postcondition-ambiguity/index.html index c684fbd..7cbd841 100644 --- a/ib002/algorithms-correctness/postcondition-ambiguity/index.html +++ b/ib002/algorithms-correctness/postcondition-ambiguity/index.html @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ This will ensure that even if the maximum in the original array was the first element, I will always satisfy that 2nd part of the loop invariant.
def broken_select_sort(arr, n):
assert n == len(arr)

if not arr:
return

max_value = max(arr)

check_loop_invariant(arr, n, n)
for i in reversed(range(n)):
arr[i] = max_value + i

check_loop_invariant(arr, n, i)

return arr
tip

There is also an easier way to break this, I leave that as an exercise ;)

Property-based tests for our sorts

Since we have talked a lot about proofs at the seminar, I would like to demonstrate it on the testing of the sorts. In the following text I will cover implementation of the loop invariant and both postconditions we have talked about and then test our sorts using them.

Loop invariant

To check loop invariant I have implemented this function:

def check_loop_invariant(arr, n, i):
# A[i + 1 : n] is sorted
for x, y in zip(itertools.islice(arr, i + 1, n), itertools.islice(arr, i + 2, n)):
assert x <= y

# all elements of A[i + 1 : n] are bigger or equal to the other elements
if i + 1 >= n:
# in case there are no elements
return

# otherwise, since the "tail" is sorted, we can assume that it is enough to
# check the other elements to the smallest value of the tail
smallest = arr[i + 1]
for element in itertools.islice(arr, i + 1):
assert smallest >= element

First part checks if the "ending" of the array is sorted.

In second part I have used a dirty trick of taking just the first element that is the smallest and compared the rest of the elements to it. Why is it enough? I leave it as an exercise ;)

Postcondition(s)

I have defined both the vague and explicit postconditions:

def check_vague_postcondition(original_arr, arr):
if not arr:
return

# check ordering
for x, y in zip(arr, itertools.islice(arr, 1, len(arr))):
assert x <= y


def check_postcondition(original_arr, arr):
if not arr:
return

# check ordering
for x, y in zip(arr, itertools.islice(arr, 1, len(arr))):
assert x <= y

# get counts from original list
original_counts = {}
for value in original_arr:
original_counts[value] = 1 + original_counts.get(value, 0)

# get counts from resulting list
counts = {}
for value in arr:
counts[value] = 1 + counts.get(value, 0)

# if arr is permutation of original_arr then all counts must be the same
assert counts == original_counts

Putting it together

Now that we have everything implement, we can move on to the implementation of the tests:

from hypothesis import given, settings
from hypothesis.strategies import integers, lists
import pytest

@given(lists(integers()))
@settings(max_examples=1000)
@pytest.mark.parametrize(
"postcondition", [check_vague_postcondition, check_postcondition]
)
@pytest.mark.parametrize("sorting_function", [select_sort, broken_select_sort])
def test_select_sort(sorting_function, postcondition, numbers):
result = sorting_function(numbers[:], len(numbers))
postcondition(numbers, result)

Since it might seem a bit scary, I will disect it by parts.

  1. Parameters of test function

    def test_select_sort(sorting_function, postcondition, numbers):

    We are given 3 parameters:

    • sorting_function - as the name suggests is the sorting function we test
    • postcondition - as the name suggests is the postcondition that we check
    • numbers - is random list of numbers that we will be sorting
  2. Body of the test

    result = sorting_function(numbers[:], len(numbers))
    postcondition(numbers, result)

    We pass to the sorting function copy of the numbers we got, this ensures that once we are checking the more strict postcondition, we can gather the necessary information even after sorting the list in-situ, i.e. we can check if the result is really a permutation of the numbers even though the sorting functions has modified the passed in list.

caution

Now we get to the more complicated part and it is the decorators.

  1. 1st parametrize from the bottom

    @pytest.mark.parametrize("sorting_function", [select_sort, broken_select_sort])

    This tells pytest, that we want to pass the values from the list to the parameter sorting_function. In other words, this lets us use the same test function for both the correct and incorrect select sort.

  2. 2nd parametrize from the bottom is similar, but works with the postcondition. The reason why they are separated is pretty simple, this way they act like cartesian product: for each sorting function we also use each postcondition.

  3. @settings raises the count of tests that hypothesis runs (from default of 100(?)).

  4. @given(lists(integers())) This means hypothesis is randomly creating lists of integers and passing them to the function, which has only one parameter left and that is numbers.

Let's run the tests!

In case you want to experiment locally, you should install pytest and hypothesis from the PyPI.

% pytest -v test_sort.py
=================================== test session starts ====================================
platform linux -- Python 3.6.8, pytest-3.8.2, py-1.7.0, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/xfocko/git/xfocko/ib002/postcondition-ambiguity, inifile:
plugins: hypothesis-5.16.1
collected 4 items

test_sort.py::test_select_sort[select_sort-check_vague_postcondition] PASSED [ 25%]
test_sort.py::test_select_sort[select_sort-check_postcondition] PASSED [ 50%]
test_sort.py::test_select_sort[broken_select_sort-check_vague_postcondition] PASSED [ 75%]
test_sort.py::test_select_sort[broken_select_sort-check_postcondition] FAILED [100%]

========================================= FAILURES =========================================
_________________ test_select_sort[broken_select_sort-check_postcondition] _________________

sorting_function = <function broken_select_sort at 0x7fac179308c8>
postcondition = <function check_postcondition at 0x7fac1786d1e0>

@given(lists(integers()))
> @settings(max_examples=1000)
@pytest.mark.parametrize(
"postcondition", [check_vague_postcondition, check_postcondition]
)
@pytest.mark.parametrize("sorting_function", [select_sort, broken_select_sort])
def test_select_sort(sorting_function, postcondition, numbers):

test_sort.py:132:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
test_sort.py:139: in test_select_sort
postcondition(numbers, result)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

original_arr = [0, 0], arr = [0, 1]

def check_postcondition(original_arr, arr):
if not arr:
return

# check ordering
for x, y in zip(arr, itertools.islice(arr, 1, len(arr))):
assert x <= y

# get counts from original list
original_counts = {}
for value in original_arr:
original_counts[value] = 1 + original_counts.get(value, 0)

# get counts from resulting list
counts = {}
for value in arr:
counts[value] = 1 + counts.get(value, 0)

# if arr is permutation of original_arr then all counts must be the same
> assert counts == original_counts
E assert {0: 1, 1: 1} == {0: 2}
E Differing items:
E {0: 1} != {0: 2}
E Left contains more items:
E {1: 1}
E Full diff:
E - {0: 1, 1: 1}
E + {0: 2}

test_sort.py:128: AssertionError
----------------------------------- Captured stdout call -----------------------------------
Falsifying example: test_select_sort(
sorting_function=<function test_sort.broken_select_sort>,
postcondition=<function test_sort.check_postcondition>,
numbers=[0, 0],
)
============================ 1 failed, 3 passed in 6.84 seconds ============================

We can clearly see that our broken select sort has passed the vague postcondition, but the explicit one was not satisfied.

Summary

For proving the correctness of the algorithm it is better to be explicit than prove that algorithm is correct even though it is not. Being explicit also allows you to test smaller chunks of code better.

- + \ No newline at end of file diff --git a/ib002/category/algorithms-and-correctness/index.html b/ib002/category/algorithms-and-correctness/index.html index d241172..06ca03b 100644 --- a/ib002/category/algorithms-and-correctness/index.html +++ b/ib002/category/algorithms-and-correctness/index.html @@ -17,7 +17,7 @@ correctness. - + @@ -27,7 +27,7 @@ correctness.

- + \ No newline at end of file diff --git a/ib002/category/asymptotic-notation-and-time-complexity/index.html b/ib002/category/asymptotic-notation-and-time-complexity/index.html index 4cf76db..e13bf8b 100644 --- a/ib002/category/asymptotic-notation-and-time-complexity/index.html +++ b/ib002/category/asymptotic-notation-and-time-complexity/index.html @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@

- + \ No newline at end of file diff --git a/ib002/category/graphs/index.html b/ib002/category/graphs/index.html index 9b694dd..fb56d2c 100644 --- a/ib002/category/graphs/index.html +++ b/ib002/category/graphs/index.html @@ -15,7 +15,7 @@ - + @@ -26,7 +26,7 @@

- + \ No newline at end of file diff --git a/ib002/category/recursion/index.html b/ib002/category/recursion/index.html index 8218530..12d68f0 100644 --- a/ib002/category/recursion/index.html +++ b/ib002/category/recursion/index.html @@ -15,7 +15,7 @@ - + @@ -26,7 +26,7 @@

- + \ No newline at end of file diff --git a/ib002/category/red-black-trees/index.html b/ib002/category/red-black-trees/index.html index a5e77a9..0f8da97 100644 --- a/ib002/category/red-black-trees/index.html +++ b/ib002/category/red-black-trees/index.html @@ -15,7 +15,7 @@ - + @@ -26,7 +26,7 @@

- + \ No newline at end of file diff --git a/ib002/graphs/bfs-tree/index.html b/ib002/graphs/bfs-tree/index.html index 9a699fa..732fbb1 100644 --- a/ib002/graphs/bfs-tree/index.html +++ b/ib002/graphs/bfs-tree/index.html @@ -15,7 +15,7 @@ - + @@ -25,7 +25,7 @@

Let's consider pair of vertices ee and hh. For them we can safely lay, from the BFS tree, following properties:

  • lower bound: 22
  • upper bound: 44

By having a look at the graph we started from, we can see that we have a path ‹e,j,he, j, h› that has a length 2. Apart from that we can also notice there is another path from ee to hh and that is ‹e,a,c,i,d,he, a, c, i, d, h›. And that path has a length of 55. Doesn't this break our statements at the beginning? (I'm leaving that as an exercise ;))

Proof by contradiction

Let's keep the same graph, but break the lower bound, i.e. I have gotten a lower bound 22, but “there must be a shorter path”! ;)

Now the more important question, is there a shorter path in that graph? The answer is no, there's no shorter path than the one with length 22. So what can we do about it? We'll add an edge to have a shorter path. Now we have gotten a lower bound of 22, which means the only shorter path we can construct has 11 edge and that is ‹e,he, h› (no intermediary vertices). Let's do this!

Okay, so we have a graph that breaks the rule we have laid. However, we need to run BFS to obtain the new BFS tree, since we have changed the graph.

tip

Do we need to run BFS after every change?

­I am leaving that as an exercise ;)

Oops, we have gotten a new BFS tree, that has a height difference of 1.

tip

Try to think about a way this can be generalized for shortening of minimal length 3 to minimal length 2 ;)

- + \ No newline at end of file diff --git a/ib002/graphs/iterative-and-iterators/index.html b/ib002/graphs/iterative-and-iterators/index.html index a94a6ed..7f44d46 100644 --- a/ib002/graphs/iterative-and-iterators/index.html +++ b/ib002/graphs/iterative-and-iterators/index.html @@ -15,13 +15,13 @@ - +

Iterative algorithms via iterators

Introduction

As we have talked on the seminar, iterative approach to implementing DFS is not very intuitive and is a very easy way how to create an incorrect implementation.

On the other hand, we have seen iterative implementation in the exercises and I have also prepared two from which one was similar to recursive implementation without colors from exercises and the other one used features of high-level languages.

Different implementations

Recursive DFS implementation from exercises without colors

function VisitedDFS(u: Vertex, visited: VertexSet) return VertexSet is
v: Vertex;
begin
visited.Union(To_Set(u));

for v in u.successors loop
if not Contains(visited, v) then
visited := visitedDFS(v, Visited);
end if;
end loop;

return visited;
end VisitedDFS;

This implementation is correct, does the DFS traversal as it should, however it has one “smallish” downside and that is the time complexity. The usage of set raises the time complexity, of course it is implementation dependant. However in case of either RB-tree or hash-table implementation, we get look-up in time O(n)\mathcal{O}(n) for hash-table in worst-case or O(logn)\mathcal{O}(\log n) for the other in the worst-case. Both are not ideal compared to checking color on vertex.

Iterative DFS from the exercises

procedure IterDFS(u: Vertex) is
stack: StateVector;
i, time: Integer;
v: Vertex;
begin
stack.Append(VertexState(u, 0));
u.color := Gray;
time := 1;
u.d := time;

while not stack.Is_Empty loop
u := stack.Last_Element.Vertex;
i := stack.Last_Element.NextIndex;
stack.Delete_Last;

if i < u.successors.Length then
-- search is not finished, is pushed back to stack
stack.Append(VertexState(u, k + 1));

v := u.successors.Element(i);
if v.color = White then
stack.Append(VertexState(v, 0));
v.color := Gray;
time := time + 1;
v.d := time;
end if;
else
-- u has no other successors, we can finish the search
time := time + 1;
u.f := time;
u.color := Black;
end if;
end loop;

end IterDFS;

As we can see, there is some ordering in which we search through the successors. Time complexity is OK, stack holds at most all vertices (they must be on the current path).

My iterative with path in stack

procedure DFS(start: Vertex) is
path: VertexVector;
time: Integer;
hasSuccessor: Bool;
successor: Vertex;
begin
path.Append(start);
time := 1;

start.d := time;
start.color := Gray;

while not path.Is_Empty loop
hasSuccessor := false;

for successor in path.Last_Element.successors loop
if successor.color = White then
hasSuccessor := true;

successor.d := time + 1;
successor.color := Gray;
time := time + 1;

path.Append(successor);

exit;
end if;
end loop;

if not hasSuccessor then
path.Last_Element.f := time + 1;
path.Last_Element.color := Black;

time := time + 1;
path.Delete_Last;
end if;

end loop;
end DFS;

This approach is similar to the iterative solution from the exercises, but it does not keep the index of the next successor, therefore it always iterates through all of them, which raises the time complexity.

My iterative solution with iterators

On the other hand, we do not actually have to depend on the representation of the graph. In this case, we just somehow obtain the iterator (which yields all of the succesors) and keep it in the stack.

procedure DFS(start: Vertex) is
path: StateVector;
time: Integer;
current: State;
nextVertex: Vertex;
begin
path.Append(State(start));
time := 1;

start.d := time;
start.color := Gray;

while not path.Is_Empty loop
current := path.Last_Element;

if not Move_Next(current.successors) then
path.Delete_Last;

time := time + 1;
current.vertex.f := time;

current.vertex.color := Black;
else if current.successors.Value.color = white then
nextVertex := current.successors.Value;

time := time + 1;
nextVertex.d := time;

nextVertex.color := Gray;

path.Append(State(nextVertex));
end if;
end loop;
end DFS;

( The way we manipulate with the iterators is closest to the C# implementation. Apart from the Iterator thing :) In case you tried to implement it in C++, you would more than likely need to change the check, since you would get first successor right at the beginning )

So here we don't keep indices, but the iterators. We can also check existence of other successors easily: by the iterator moving after the last successor.

Closer explanation of the iterator shenanigans follows. In the beginning, either start or when pushing new vertex, we are pushing an iterator that points just before the first successor. When populating lastVertex and successors in the while-loop, we take the element from the top of the stack. MoveNext returns true if there is an element, i.e. successor in this case. If it returns false we have nothing to do and we pop the vertex from the stack (also set finishing time and color). If we have successor we check if it has been already visited or not. If has not, we set discovery time and color accordingly, also we add it to stack.

Implementation

In case you want to play around with the code. At the beginning there is a link to the C# implementation that can be used. It has a basic representation of graph and includes BFS/DFS implementation in classes.

In Program.cs you can also find a method that returns graph we used on the seminar.

- + \ No newline at end of file diff --git a/ib002/index.html b/ib002/index.html index 2e08c88..d9ef635 100644 --- a/ib002/index.html +++ b/ib002/index.html @@ -13,7 +13,7 @@ - + @@ -21,8 +21,8 @@

Introduction

In this part you can find “random” additional materials I have written over the course of teaching Algorithms and data structures I.

It is a various mix of stuff that may have been produced as a follow-up on some question asked at the seminar or spontanously.

If you have some ideas for posts, please do not hesitate to submit them as issues -in the linked GitLab.

- +in the linked GitLab.

+ \ No newline at end of file diff --git a/ib002/rb-trees/applications/index.html b/ib002/rb-trees/applications/index.html index b9e5a44..9ee4291 100644 --- a/ib002/rb-trees/applications/index.html +++ b/ib002/rb-trees/applications/index.html @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@

Použití červeno-černých stromů

Použití

Červeno-černé stromy jsou celkem oblíbené pro implementaci ADT množiny nebo slovníku za předpokladu, že nad vkládanými klíči existuje uspořádání. Jazyky níže implementují dané datové struktury v 2 variantách a to:

  • seřazené: používají na pozadí právě červeno-černý strom
  • neseřazené: používají na pozadí hašovací tabulku

Pro srovnání, jak jsme si říkali na cvičení, červeno-černý strom má operace hledání, vkládání a mazání v časové složitosti O(logn)\mathcal{O}(\log n). Na druhou stranu hašovací tabulka má ideálně konstantní časovou složitost, ale v nejhorším případě (detaily na posledním cvičení v semestru) je to bohužel O(n)\mathcal{O}(n).

Výše jsme si ukázali nějaké předpoklady nutné pro hašovací tabulku i červeno-černý strom. Co je tedy lepší?

  • červeno-černý strom nám poskytuje stabilní časovou složitost, ale za cenu požadavku uspořádání nad prvky
  • hašovací tabulka nám poskytuje pomyslnou perfektní časovou složitost

Různé implementace

Pro ukázku použití červeno-černých stromů v implementacích standardních knihoven jsme vybrali několik jazyků.

Pokud Vás zajímají různé implementace, tak bychom doporučili „prohrabávat“ se přes ně v následujícím pořadí: C# → Java → C++. Důvod pro zvolené pořadí vychází z toho, že C# implementace je poměrně čitelná a obsahuje množství vysvětlujících komentářů. Implementace v Javě je stejně čitelná, ačkoli již s minimem komentářů, které se maximálně odkazují na CLRS. C++ implementace je „značně poznačená“ podtržítky ;)

C++

V C++ si můžeme vybrat mezi 2 různými implementacemi (clang nebo gcc).

clang

Hlavičkové soubory, které používáme při práci s množinou nebo slovníkem (zajímavé sekce jsou vytaženy):

  • map

    template <class _Key, class _Tp, class _Compare = less<_Key>,
    class _Allocator = allocator<pair<const _Key, _Tp> > >
    class _LIBCPP_TEMPLATE_VIS map
    {
    public:
    // types:
    typedef _Key key_type;
    typedef _Tp mapped_type;
    typedef pair<const key_type, mapped_type> value_type;

    // …

    private:
    typedef __tree<__value_type, __vc, __allocator_type> __base;
  • set

    template <class _Key, class _Compare = less<_Key>,
    class _Allocator = allocator<_Key> >
    class _LIBCPP_TEMPLATE_VIS set
    {
    public:
    // types:
    typedef _Key key_type;
    typedef key_type value_type;

    // …

    private:
    typedef __tree<value_type, value_compare, allocator_type> __base;

U obou hlaviček si můžeme všimnout, že deklarují nějaký soukromý typ __base, který je aliasem pro __tree. Ten nás pak vede k hlavičce __tree.

Výňatek:

/*

_NodePtr algorithms

The algorithms taking _NodePtr are red black tree algorithms. Those
algorithms taking a parameter named __root should assume that __root
points to a proper red black tree (unless otherwise specified).



*/

gcc

Pro gcc je postup téměř stejný. Pro změnu v hlavičkách map a set nenajdeme nic, deklarace jsou až v hlavičkových souborech:

V obou se zase odkazuje na nějakou hlavičku bits/stl_tree.h, zase výňatek:

  // Red-black tree class, designed for use in implementing STL
// associative containers (set, multiset, map, and multimap). The
// insertion and deletion algorithms are based on those in Cormen,
// Leiserson, and Rivest, Introduction to Algorithms (MIT Press,
// 1990), except that
//
// (1) the header cell is maintained with links not only to the root
// but also to the leftmost node of the tree, to enable constant
// time begin(), and to the rightmost node of the tree, to enable
// linear time performance when used with the generic set algorithms
// (set_union, etc.)
//
// (2) when a node being deleted has two children its successor node
// is relinked into its place, rather than copied, so that the only
// iterators invalidated are those referring to the deleted node.

enum _Rb_tree_color { _S_red = false, _S_black = true };

struct _Rb_tree_node_base
{
typedef _Rb_tree_node_base* _Base_ptr;
typedef const _Rb_tree_node_base* _Const_Base_ptr;

_Rb_tree_color _M_color;
_Base_ptr _M_parent;
_Base_ptr _M_left;
_Base_ptr _M_right;

static _Base_ptr
_S_minimum(_Base_ptr __x) _GLIBCXX_NOEXCEPT
{
while (__x->_M_left != 0) __x = __x->_M_left;
return __x;
}

static _Const_Base_ptr
_S_minimum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT
{
while (__x->_M_left != 0) __x = __x->_M_left;
return __x;
}

static _Base_ptr
_S_maximum(_Base_ptr __x) _GLIBCXX_NOEXCEPT
{
while (__x->_M_right != 0) __x = __x->_M_right;
return __x;
}

static _Const_Base_ptr
_S_maximum(_Const_Base_ptr __x) _GLIBCXX_NOEXCEPT
{
while (__x->_M_right != 0) __x = __x->_M_right;
return __x;
}

Tady už taky vidíme nějaký kód pro nalezení minima/maxima ve stromě. Mimo jiné ještě existuje tree.cc, kde je lze nalézt třeba funkci s následující hlavičkou:

void
_Rb_tree_insert_and_rebalance(const bool __insert_left,
_Rb_tree_node_base* __x,
_Rb_tree_node_base* __p,
_Rb_tree_node_base& __header) throw ();

Java

V Javě jsou pro nás klíčové implementace TreeSet a TreeMap.

V implementaci TreeSet si můžete povšimnout:

public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
/**
* The backing map.
*/
private transient NavigableMap<E,Object> m;

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

TreeSet v Javě tedy používá na pozadí TreeMap (což je vidět ve výchozím konstruktoru, kde se volá konstruktor přebírající NavigableMap<E, Object>, a je mu předáno new TreeMap<>()).

Co se týče TreeMap, tak hned ze začátku definice TreeMap je vidět:

public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
/**
* The comparator used to maintain order in this tree map, or
* null if it uses the natural ordering of its keys.
*
* @serial
*/
@SuppressWarnings("serial") // Conditionally serializable
private final Comparator<? super K> comparator;

private transient Entry<K,V> root;

Takže máme „nějaký kořen“ typu Entry<K,V>. Zkusíme si najít definici daného typu…

    // Red-black mechanics

private static final boolean RED = false;
private static final boolean BLACK = true;

/**
* Node in the Tree. Doubles as a means to pass key-value pairs back to
* user (see Map.Entry).
*/

static final class Entry<K,V> implements Map.Entry<K,V> {
K key;
V value;
Entry<K,V> left;
Entry<K,V> right;
Entry<K,V> parent;
boolean color = BLACK;

A máme RB-tree.

(Implementace vychází z projektu OpenJDK.)

C#

V C# se zaměříme na nejnovější vydání (.NET), které je open-source a podporováno i na operačních systémech založených na Linuxu.

Nejdříve se podíváme na implementaci slovníku (SortedDictionary).

    public class SortedDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue> where TKey : notnull
{
[NonSerialized]
private KeyCollection? _keys;
[NonSerialized]
private ValueCollection? _values;

private readonly TreeSet<KeyValuePair<TKey, TValue>> _set; // Do not rename (binary serialization)

Na první pohled máme problém, protože TreeSet není SortedSet, který by jsme čekali. Když se přesuneme na konec souboru, tak zjistíme, že TreeSet je jenom backward-compatible wrapper pro SortedSet.

Přesuneme se k SortedSet. A hned ze začátku vidíme:

    // A binary search tree is a red-black tree if it satisfies the following red-black properties:
// 1. Every node is either red or black
// 2. Every leaf (nil node) is black
// 3. If a node is red, the both its children are black
// 4. Every simple path from a node to a descendant leaf contains the same number of black nodes
//
// The basic idea of a red-black tree is to represent 2-3-4 trees as standard BSTs but to add one extra bit of information
// per node to encode 3-nodes and 4-nodes.
// 4-nodes will be represented as: B
// R R
//
// 3 -node will be represented as: B or B
// R B B R
//
// For a detailed description of the algorithm, take a look at "Algorithms" by Robert Sedgewick.

internal enum NodeColor : byte
{
Black,
Red
}

internal delegate bool TreeWalkPredicate<T>(SortedSet<T>.Node node);

internal enum TreeRotation : byte
{
Left,
LeftRight,
Right,
RightLeft
}

Vysvětlení v komentáři trochu předbíhá náplň cvičení zaměřeného na B-stromy ;)

Vztah mezi množinou a mapou

Při každé implementaci ve standardní knihovně jsme si mohli všimnout, že strom implementuje vždy jenom jeden typ:

JazykZpůsob implementace
C++mapa ukládá dvojice do množiny
Javamnožina ukládá prvky s „dummy“ hodnotou do mapy
C#mapa ukládá dvojice do množiny

Mapa vyžaduje, aby každý klíč měl přiřazenou právě jednu hodnotu, tedy klíče jsou navzájem mezi sebou unikátní. To nám umožňuje organizovat klíče do množiny, zde ale narazíme na nepříjemný problém spočívající v tom, že musíme do množiny vkladat dvojice prvků: (key, value). Tenhle přístup má ale zásadní problém:

# let's represent dictionary/map as a set
set_of_values = set()

# let's insert few pairs
set_of_values.add((1, 2))
set_of_values.add((0, 42))

# let's set key 1 to value 6
set_of_values.add((1, 6))

set_of_values

A dostaneme:

{(1, 6), (1, 2), (0, 42)}

V jednotlivých implementacích, které jste mohli vidět výše, se využívá nasledující, když:

  • mapa ukládá dvojice do množiny: Dvojice je obalená v samostatním typu, který porovnává jenom klíče
  • množina ukládá klíče do mapy: V mapě se ignorují hodnoty přiřazené klíčům
- + \ No newline at end of file diff --git a/ib002/rb-trees/rules/index.html b/ib002/rb-trees/rules/index.html index 9278760..4ecfa1d 100644 --- a/ib002/rb-trees/rules/index.html +++ b/ib002/rb-trees/rules/index.html @@ -15,7 +15,7 @@ - + @@ -101,7 +101,7 @@ tree, the only difference is that it does not deal with the black height

If you were to compare AVL with the red-black tree, you can say that AVL is much more strict while red-black tree can still maintain the same asymptotic time complexity for the operations, but having more relaxed rules.


  1. CORMEN, Thomas. Introduction to algorithms. Cambridge, Mass: MIT Press, 2009. isbn 9780262033848.
  2. red nodes still exist
- + \ No newline at end of file diff --git a/ib002/recursion/karel-1/index.html b/ib002/recursion/karel-1/index.html index 52b47b6..c713511 100644 --- a/ib002/recursion/karel-1/index.html +++ b/ib002/recursion/karel-1/index.html @@ -15,7 +15,7 @@ - + @@ -46,7 +46,7 @@ as karel_tk.py and takes path to the world as a first argument, exa it out by yourself without any influence of “example solution”.

If you want to get any feedback, feel free to mail me your solution (including all the steps that lead to your final solution, if you wish to get feedback on those too).

- + \ No newline at end of file diff --git a/ib002/recursion/pyramid-slide-down/index.html b/ib002/recursion/pyramid-slide-down/index.html index dd41563..9a4d3e1 100644 --- a/ib002/recursion/pyramid-slide-down/index.html +++ b/ib002/recursion/pyramid-slide-down/index.html @@ -15,7 +15,7 @@ - + @@ -135,8 +135,8 @@ can't do whatever we want with it.

Example #1

Let us assume function that uses divide & conquer strategy to return indices at which we can find specific element in any list.

def recursive_find_in_list(
values: List[Any], key: Any, lower: int, upper: int
) -> List[int]:
if lower == upper:
return [lower] if values[lower] == key else []

indices = []
mid = (lower + upper) // 2

indices.extend(recursive_find_in_list(values, key, lower, mid))
indices.extend(recursive_find_in_list(values, key, mid + 1, upper))

return indices


def find_in_list(values: List[Any], key: Any) -> List[int]:
return recursive_find_in_list(values, key, 0, len(values) - 1)

This implementation works nicely, extend is linear (with the respect to the length of the list that is being appended).

Let us try to dissect the way this function works on some specific input (that will be pushed to the extreme, just in case ;)

find_in_list([1] * 5000, 1). What shall be the result of this? Since we have key = 1 and the list contains only 1s, we should get list of all indices.

If we were to draw a tree of call hierarchy of recursive_find_in_list, we would notice that in sum it is still linear to the length. However we use extend!

In the leaves of the tree we return lists of length 1. In this case it means calling extend 5000-times at the second-to-last level of the tree on the 1-element long lists, next level 2500 calls on 2-elements long lists, next one 1250 on 4-elements long lists, etc. At the top-level we get 2 calls on 5000/2-element long lists.

A lot of extend calls, right? And the lengths of the lists are growing (in this example, second call happens on 2500-elements long lists).

Because of the extend in each level of the tree (call hierarchy) we traverse all of the elements. That means:

O(nlogn)\mathcal{O}(n \cdot \log n)

because we have logn\log n levels in the tree and nn elements at each level.

Example #2

As we could observe in the example above, extend iterates over all of the elements that it adds. In case of recursive calls, it results in iterating over the same elements multiple times.

Consider constructing of this list:

Rendered construction of the list Rendered construction of the list

Let us assume that you extend the result with the list that you get from the recursive call.

  • B iterates through 1, 2 and 3; returns [1, 2, 3]

  • C iterates through 4, 5 and 6; returns [4, 5, 6]

  • D iterates through 7, 8 and 9; returns [7, 8, 9]

  • now we return those lists to the calls from A), so each of the extend calls iterates through:

    • 1, 2, 3 that was returned from B
    • 4, 5, 6 that was returned from C
    • 7, 8, 9 that was returned from D

    and returns [1, 2, 3, 4, 5, 6, 7, 8, 9]

If the recursion had bigger depth and/or more elements, it would iterate through them more than twice, therefore it does not take constant time to do nor some constant multiple of the input, since it traverses all of the elements in each of the levels.

Implementation of extend

There is an example of dynamic array:

For the sake of Algorithms and Data Structures I we consider APPEND operation, i.e. adding the element to the end of the list, to have time complexity O(1)\mathcal{O}(1) (amortized; which is out of the scope of IB002).

If we have a look at the extend implementation in this dynamic array example:

void dynamic_array_extend(struct dynamic_array_t *arr, struct dynamic_array_t *src)
{
if (arr == NULL || src == NULL)
{
return;
}

for (size_t i = 0; i < src->count; i++)
{
dynamic_array_push_back(arr, dynamic_array_at(src, i));
}
}

Apart from checking edge cases, we can notice that we run for-loop over the elements from the other array and add them one-by-one to the arr. Time complexity of this operation is time dependant on the src array.

In this specific implementation, you could also resize the memory allocated for the array in one go and copy whole src array in one go. However even if you did so, it would be still dependant on the size of the src array. Cause you still need to copy count(src)elementSize(src)\texttt{count}(src) \cdot \texttt{elementSize}(src) bytes. From that we can assume that for specific instance of array the elementSize(src)\texttt{elementSize}(src) is fixed, therefore we consider it a constant. That way we are getting O(count(src))\mathcal{O}(\texttt{count}(src)) as a time complexity of our extend operation.

- + \ No newline at end of file diff --git a/index.html b/index.html index c21ab7b..2083582 100644 --- a/index.html +++ b/index.html @@ -13,13 +13,13 @@ - +

mf

blog and additional materials for courses at φ

About Me

I'm working in Red Hat in the Packit team and studying at FI MUNI while also tutoring some courses there.

Content

On this page you can find my blog or unofficial materials I have written over the course of teaching multiple courses at the FI.

Mastodon

Feel free to contact me on any of the following Mastodon accounts: Fosstodon or Hachyderm.io

- + \ No newline at end of file diff --git a/pb071/bonuses/seminar-03/index.html b/pb071/bonuses/seminar-03/index.html index d575bfb..09e2593 100644 --- a/pb071/bonuses/seminar-03/index.html +++ b/pb071/bonuses/seminar-03/index.html @@ -15,7 +15,7 @@ - + @@ -35,7 +35,7 @@ to get its address.) And you can also call the function by “calling” the fun pointer, e.g. comp(left, right).

Submitting

For submitting the bonus assignment you can follow the same procedure as for submitting the homeworks, that is:

  1. On branch main add the provided skeleton.
  2. Checkout new branch seminar-bonus-03.
  3. Add your solution to the newly created branch.
  4. Create a MR to the main branch with me (@xfocko) as the reviewer.
Directory structure for bonuses

Ideally create a directory seminar-bonuses in the root of your repository with bonuses in their own subdirectories.

Structure of your repository can look like this:

.
├── bonuses
│ └── seminar-03
├── hello
├── hw01
├── hw02
├── seminar-01
├── seminar-02
└── seminar-03

or

.
├── bonus-seminar-03
├── hello
├── hw01
├── hw02
├── seminar-01
├── seminar-02
└── seminar-03

Structure of the bonuses is entirely up to you, just keep it consistent.

- + \ No newline at end of file diff --git a/pb071/bonuses/seminar-04/index.html b/pb071/bonuses/seminar-04/index.html index f607df6..84df0c8 100644 --- a/pb071/bonuses/seminar-04/index.html +++ b/pb071/bonuses/seminar-04/index.html @@ -15,7 +15,7 @@ - + @@ -40,7 +40,7 @@ you want.
  • I keep only one copy of cut.h in my only once, so it doesn't take up more space.

  • I would recommend cloning this repository and copying the maze directory to your own repository, since there are multiple files and it may be easier for you.

  • In case you have any questions, feel free to reach out to me.

    Submitting

    For submitting the bonus assignment you can follow the same procedure as for submitting the homeworks, that is:

    1. On branch main add the provided skeleton.
    2. Checkout new branch seminar-bonus-04.
    3. Add your solution to the newly created branch.
    4. Create a MR to the main branch with me (@xfocko) as the reviewer.
    - + \ No newline at end of file diff --git a/pb071/bonuses/seminar-05-06/index.html b/pb071/bonuses/seminar-05-06/index.html index 7e2c937..3c6f7b2 100644 --- a/pb071/bonuses/seminar-05-06/index.html +++ b/pb071/bonuses/seminar-05-06/index.html @@ -15,7 +15,7 @@ - + @@ -39,8 +39,8 @@ so we will demonstrate on letter H:

    1. Letter H0000, which we got from the 3rd step) and get 10000000, which is encrypted character H using this method.

    In case of decryption, reverse those steps.

    Your task is to implement functions:

    • unsigned char* bit_encrypt(const char* text)
    • char* bit_decrypt(const unsigned char* text)

    Example:

    unsigned char* encrypted = bit_encrypt("Hello world!");

    for (int i = 0; i < 12;i++) {
    printf("%x ", encrypted[i]);
    //80 9c 95 95 96 11 bc 96 b9 95 9d 10
    }

    if (encrypted != NULL) {
    free(encrypted);
    }

    Task no. 4: All combined to BMP (0.5 K₡)

    Authors of the BMP cipher are non-disclosed :)

    Create pair of functions:

    • unsigned char* bmp_encrypt(const char* key, const char* text)
    • char* bmp_decrypt(const char* key, const unsigned char* text)

    BMP cipher consists of following steps for encrypting:

    1. Reverse the input string
    2. Use Vigenere on the string you got from step #1
    3. Use bit madness on the string you got from step #2

    For decrypting, reverse the steps.

    Submitting

    In case you have any questions, feel free to reach out to me.


    Ideally submit the assignment through the merge request. Step-by-step tutorial is present here. For setting assignee my xlogin is xfocko.

    In case you do not want to experiment on GitLab, send me the source code via email, -but please prefix subject with: [PB071/14][seminar-05-06]

    Deadline for the submission of the bonus is April 21th 24:00.

    - +but please prefix subject with: [PB071/14][seminar-05-06]

    Deadline for the submission of the bonus is April 21th 24:00.

    + \ No newline at end of file diff --git a/pb071/bonuses/seminar-08/index.html b/pb071/bonuses/seminar-08/index.html index 2e4cb70..48d0491 100644 --- a/pb071/bonuses/seminar-08/index.html +++ b/pb071/bonuses/seminar-08/index.html @@ -15,7 +15,7 @@ - + @@ -43,8 +43,8 @@ through the tree. Leaves never have rank different than 0, so you can safely ass 2 non-existing nils in the input after you read such node ;)

    Example input fileTree it represents
    8;4
    5;3
    3;2
    2;1
    1;0
    nil
    4;0
    7;1
    6;0
    nil
    11;2
    10;1
    9;0
    nil
    12;0

    tree

    In this task you are only provided with different trees in the test-trees directory. Implementation and format of the pretty-print is totally up to you. :)

    Example of mine for the tree above:

    8 (rank = 4)
    +-- 5 (rank = 3)
    | +-- 3 (rank = 2)
    | | +-- 2 (rank = 1)
    | | | +-- 1 (rank = 0)
    | | +-- 4 (rank = 0)
    | +-- 7 (rank = 1)
    | +-- 6 (rank = 0)
    +-- 11 (rank = 2)
    +-- 10 (rank = 1)
    | +-- 9 (rank = 0)
    +-- 12 (rank = 0)

    Can you find out what are those trees? :)

    Submitting

    In case you have any questions, feel free to reach out to me.


    Ideally submit the assignment through the merge request. Step-by-step tutorial is present here. For setting assignee my xlogin is xfocko.

    In case you do not want to experiment on GitLab, send me the source code via email, -but please prefix subject with: [PB071/14][seminar-08]

    Deadline for the submission of the bonus is May 4th 24:00.

    - +but please prefix subject with: [PB071/14][seminar-08]

    Deadline for the submission of the bonus is May 4th 24:00.

    + \ No newline at end of file diff --git a/pb071/bonuses/seminar-10/index.html b/pb071/bonuses/seminar-10/index.html index 5935f3e..dd6c0b6 100644 --- a/pb071/bonuses/seminar-10/index.html +++ b/pb071/bonuses/seminar-10/index.html @@ -15,7 +15,7 @@ - + @@ -46,8 +46,8 @@ much of the duplicit code as possible.

    Tests should help you a lot in case is because of the get_word bug. It is not a bug that can be easily fixed, so it is a not requirement at all and you can still get all points for the bonus ;)

    Dictionary

    Submitting

    In case you have any questions, feel free to reach out to me.


    Ideally submit the assignment through the merge request. Step-by-step tutorial is present here. For setting assignee my xlogin is xfocko.

    In case you do not want to experiment on GitLab, send me the source code via -email, but please prefix subject with: [PB071/14][seminar-10]

    Deadline for the submission of the bonus is May 17 24:00.

    - +email, but please prefix subject with: [PB071/14][seminar-10]

    Deadline for the submission of the bonus is May 17 24:00.

    + \ No newline at end of file diff --git a/pb071/category/bonuses/index.html b/pb071/category/bonuses/index.html index 6e3c4f1..6f4b22c 100644 --- a/pb071/category/bonuses/index.html +++ b/pb071/category/bonuses/index.html @@ -15,7 +15,7 @@ - + @@ -32,7 +32,7 @@

    - + \ No newline at end of file diff --git a/pb071/category/practice-exams/index.html b/pb071/category/practice-exams/index.html index ee65e63..d15a7b9 100644 --- a/pb071/category/practice-exams/index.html +++ b/pb071/category/practice-exams/index.html @@ -15,7 +15,7 @@ - + @@ -26,7 +26,7 @@

    - + \ No newline at end of file diff --git a/pb071/index.html b/pb071/index.html index abcb6dc..9f1ab88 100644 --- a/pb071/index.html +++ b/pb071/index.html @@ -13,13 +13,13 @@ - + - + + \ No newline at end of file diff --git a/pb071/mr/index.html b/pb071/mr/index.html index 3b5d45d..85d688e 100644 --- a/pb071/mr/index.html +++ b/pb071/mr/index.html @@ -13,7 +13,7 @@ - + @@ -42,8 +42,8 @@ for the course. Because of that, before you do anything else, you should switch back to your default branch.

    First of all, same as in step #1, check that your repository is clean with git status. For the sake of safety, do not continue without clean repository. Then with command git checkout BRANCH switch to your default branch BRANCH.

    If you do not know which branch is your default, try git branch that outputs all branches in your repository. Default branch is typically master, but can -be main or trunk.

    aisa$ git status
    # Check if repository is clean

    # If you know, what is your default branch, you can skip next command.
    aisa$ git branch
    # Find the default branch in the list; should be one of the `master`, `main` or
    # `trunk` and you should not have more than one of those.
    # In case the list clears the terminal and you cannot see shell prompt, you can
    # press `q` to quit the pager.

    aisa$ git checkout master

    Adapted from: https://www.fi.muni.cz/~xlacko1/pb071/mr.html

    - +be main or trunk.

    aisa$ git status
    # Check if repository is clean

    # If you know, what is your default branch, you can skip next command.
    aisa$ git branch
    # Find the default branch in the list; should be one of the `master`, `main` or
    # `trunk` and you should not have more than one of those.
    # In case the list clears the terminal and you cannot see shell prompt, you can
    # press `q` to quit the pager.

    aisa$ git checkout master

    Adapted from: https://www.fi.muni.cz/~xlacko1/pb071/mr.html

    + \ No newline at end of file diff --git a/pb071/pexam/cams/index.html b/pb071/pexam/cams/index.html index cc13a33..04f90a4 100644 --- a/pb071/pexam/cams/index.html +++ b/pb071/pexam/cams/index.html @@ -15,7 +15,7 @@ - + @@ -50,7 +50,7 @@ are just a hint to not waste your time tinkering with a user experience.
  • you are expected to handle the situation accordingly.
  • Failures of any other common functions (e.g. functions used for memory management) should be handled in the same way as they were in the homeworks and seminars.
  • Your program must free all the resources before exiting.

    1. Subject to NDA.
    - + \ No newline at end of file diff --git a/pb071/pexam/garbage_collect/index.html b/pb071/pexam/garbage_collect/index.html index 755a7f8..98a4224 100644 --- a/pb071/pexam/garbage_collect/index.html +++ b/pb071/pexam/garbage_collect/index.html @@ -15,7 +15,7 @@ - + @@ -43,7 +43,7 @@ are just a hint to not waste your time tinkering with a user experience.
  • you are expected to handle the situation accordingly.
  • Failures of any other common functions (e.g. functions used for memory management) should be handled in the same way as they were in the homeworks and seminars.
  • Your program must free all the resources before exiting.

    1. Also applies to Fedora, but… we use arch btw 😉
    2. duh!
    - + \ No newline at end of file diff --git a/pb161/environment/index.html b/pb161/environment/index.html index 7444780..c97669b 100644 --- a/pb161/environment/index.html +++ b/pb161/environment/index.html @@ -15,7 +15,7 @@ - + @@ -56,7 +56,7 @@ precompiled main for tests, e.g.

    - + \ No newline at end of file diff --git a/pb161/index.html b/pb161/index.html index 44a1cad..9d3382e 100644 --- a/pb161/index.html +++ b/pb161/index.html @@ -13,13 +13,13 @@ - + - +
    + \ No newline at end of file diff --git a/search/index.html b/search/index.html index 4812ba9..82a223c 100644 --- a/search/index.html +++ b/search/index.html @@ -13,13 +13,13 @@ - + - + \ No newline at end of file diff --git a/talks/index.html b/talks/index.html index 3fa9ef5..0b5ea56 100644 --- a/talks/index.html +++ b/talks/index.html @@ -13,13 +13,13 @@ - +

    Talks

    Featured talks I presented on various events.

    Packit: RPM integration, all in one

    Do you want to automate how you build and test your RPM packages? Do you maintain any package in Fedora and want to automate the releases? Or are you just interested in CI/CD on GitHub or GitLab, Fedora and integration of upstream projects with RPM-based Linux distributions? In this session, we are going to deep-dive into features of Packit that can help you do your day-to-day job.
    • DevConf.cz
    • Brno, Czechia
    • 6/2023

    Also presented on:

    • DevConf.cz Mini in Brno, Czechia (3/2023)

    Credits to Paweł Kosiec for implementing his own React components for talks.

    - + \ No newline at end of file