queue = new PriorityQueue<>();
71 | ListNode temp = head;
72 | while (temp.next != null) {
73 | queue.add(temp.val);
74 | temp = temp.next;
75 | }
76 | queue.add(temp.val);
77 | temp = head;
78 | //
79 | while (!queue.isEmpty()) {
80 | temp.val = queue.poll();
81 | temp = temp.next;
82 | }
83 | return head;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/sliding_window/easy/BestTimeToBuyAndSellStock.java:
--------------------------------------------------------------------------------
1 | package solution.sliding_window.easy;
2 |
3 | /**
4 | * @see Task 121
5 | */
6 | public class BestTimeToBuyAndSellStock {
7 |
8 | public int maxProfit(int[] prices) {
9 | int left = 0;
10 | int right = 1;
11 | int maxProfit = 0;
12 | while (right < prices.length) {
13 | if (prices[left] < prices[right]) {
14 | maxProfit = Math.max(maxProfit, prices[right] - prices[left]);
15 | } else {
16 | left = right;
17 | }
18 | right++;
19 | }
20 | return maxProfit;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/sliding_window/medium/LongestRepeatingCharacterReplacement.java:
--------------------------------------------------------------------------------
1 | package solution.sliding_window.medium;
2 |
3 | /**
4 | * @see Task 424
5 | */
6 | public class LongestRepeatingCharacterReplacement {
7 |
8 | public int characterReplacement(String s, int k) {
9 | int len = s.length();
10 | int[] count = new int[26];
11 | int start = 0, maxCount = 0, maxLength = 0;
12 |
13 | for (int end = 0; end < len; end++) {
14 | maxCount = Math.max(maxCount, ++count[s.charAt(end) - 'A']);
15 | while (end - start + 1 - maxCount > k) {
16 | count[s.charAt(start) - 'A']--;
17 | start++;
18 | }
19 | maxLength = Math.max(maxLength, end - start + 1);
20 | }
21 | return maxLength;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/sliding_window/medium/LongestSubstringWithoutRepeatingCharacters.java:
--------------------------------------------------------------------------------
1 | package solution.sliding_window.medium;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | /**
7 | * @see Task 3
8 | */
9 | public class LongestSubstringWithoutRepeatingCharacters {
10 |
11 | /**
12 | * Основная идея:
13 | * Мы должны итерироваться по строке и добавлять символы во множество (set), если они отсутствуют в нем.
14 | * Если символ уже присутствует во множестве, то мы должны удалить все символы, находящиеся перед этим повторением.
15 | *
16 | * Пример:
17 | * s = "asdfghjd"
18 | * Тогда мы придем к ситуации, когда set -> [a,s,d,f,g,h,j] и символ = d
19 | * Следовательно нам нужно удалить все символы до 'd', те [a,s,d]
20 | * и как результат мы получим сет [f,g,h,j,d] с уникальными элементами
21 | */
22 | public int lengthOfLongestSubstring(String s) {
23 | Set set = new HashSet<>();
24 | int max = 0;
25 | for (int i = 0; i < s.length(); i++) {
26 | char c = s.charAt(i);
27 | if (set.contains(c)) {
28 | // удаляем все до повтора
29 | while (c != s.charAt(i - set.size())) {
30 | set.remove(s.charAt(i - set.size()));
31 | }
32 | } else {
33 | set.add(c);
34 | }
35 | if (set.size() > max) max = set.size();
36 | }
37 | return max;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/stack/easy/ValidParentheses.java:
--------------------------------------------------------------------------------
1 | package solution.stack.easy;
2 |
3 | import java.util.Stack;
4 |
5 | /**
6 | * @see Task 20
7 | */
8 | public class ValidParentheses {
9 | public boolean isValid(String s) {
10 | Stack stack = new Stack<>();
11 | for (Character c : s.toCharArray()) {
12 | if (c == '(' || c == '{' || c == '[') {
13 | stack.push(c);
14 | } else {
15 | if (stack.size() == 0) return false;
16 | char lastOpen = stack.pop();
17 |
18 | if (lastOpen == '(' && c != ')') return false;
19 | if (lastOpen == '{' && c != '}') return false;
20 | if (lastOpen == '[' && c != ']') return false;
21 | }
22 | }
23 | return stack.isEmpty();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/stack/medium/EvaluateReversePolishNotation.java:
--------------------------------------------------------------------------------
1 | package solution.stack.medium;
2 |
3 | import java.util.Stack;
4 |
5 | /**
6 | * @see Task 150
7 | */
8 | public class EvaluateReversePolishNotation {
9 | public int evalRPN(String[] tokens) {
10 | Stack stack = new Stack<>();
11 | for (String s : tokens) {
12 | switch (s) {
13 | case "+":
14 | stack.push(stack.pop() + stack.pop());
15 | break;
16 | case "-":
17 | int r = stack.pop();
18 | int l = stack.pop();
19 | stack.push(l - r);
20 | break;
21 | case "*":
22 | stack.push(stack.pop() * stack.pop());
23 | break;
24 | case "/":
25 | int right = stack.pop();
26 | int left = stack.pop();
27 | stack.push(left / right);
28 | break;
29 | default:
30 | stack.push(Integer.parseInt(s));
31 | break;
32 | }
33 | }
34 | return stack.pop();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/stack/medium/GenerateParentheses.java:
--------------------------------------------------------------------------------
1 | package solution.stack.medium;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * @see Task 22
8 | */
9 | public class GenerateParentheses {
10 |
11 | public List generateParenthesis(int n) {
12 | List result = new ArrayList<>();
13 | generateParenthesis(result, n - 1, 1, "(");
14 | return result;
15 | }
16 |
17 | private void generateParenthesis(List result, int forOpen, int opened, String prefix) {
18 | if (forOpen == 0) {
19 | result.add(prefix + ")".repeat(Math.max(0, opened)));
20 | return;
21 | }
22 |
23 | if (forOpen > 0) {
24 | generateParenthesis(result, forOpen - 1, opened + 1, prefix + "(");
25 | }
26 |
27 | if (opened > 0) {
28 | generateParenthesis(result, forOpen, opened - 1, prefix + ")");
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/stack/medium/MinStack.java:
--------------------------------------------------------------------------------
1 | package solution.stack.medium;
2 |
3 |
4 | /**
5 | * @see Task 155
6 | */
7 | public class MinStack {
8 |
9 | Node defaultNode = new Node();
10 | Node head;
11 |
12 | public MinStack() {
13 | head = defaultNode;
14 | }
15 |
16 | public void push(int val) {
17 | if (head == defaultNode) {
18 | head = new Node(val, defaultNode, val);
19 | } else {
20 | head = new Node(val, head, Math.min(val, head.min));
21 | }
22 | }
23 |
24 | public void pop() {
25 | if (head != defaultNode) {
26 | head = head.prev;
27 | }
28 | }
29 |
30 | public int top() {
31 | if (head == defaultNode) return 0;
32 | return head.val;
33 | }
34 |
35 | public int getMin() {
36 | if (head == defaultNode) return 0;
37 | return head.min;
38 | }
39 |
40 | private static class Node {
41 | int val;
42 | Node prev;
43 | int min;
44 |
45 | public Node() {
46 | }
47 |
48 | public Node(int val, Node prev, int min) {
49 | this.val = val;
50 | this.prev = prev;
51 | this.min = min;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/tree/TreeNode.java:
--------------------------------------------------------------------------------
1 | package solution.tree;
2 |
3 | public class TreeNode {
4 | public int val;
5 | public TreeNode left;
6 | public TreeNode right;
7 |
8 | public TreeNode() {
9 | }
10 |
11 | public TreeNode(int val) {
12 | this.val = val;
13 | }
14 |
15 | public TreeNode(int val, TreeNode left, TreeNode right) {
16 | this.val = val;
17 | this.left = left;
18 | this.right = right;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/tree/easy/BalancedBinaryTree.java:
--------------------------------------------------------------------------------
1 | package solution.tree.easy;
2 |
3 |
4 | import solution.tree.TreeNode;
5 |
6 | /**
7 | * @see Task 110
8 | */
9 | public class BalancedBinaryTree {
10 |
11 | boolean result = true;
12 |
13 | public boolean isBalanced(TreeNode root) {
14 | getDepth(root);
15 | return result;
16 | }
17 |
18 | /**
19 | * A height-balanced binary tree is a binary tree in which the depth of the two subtrees
20 | * of every node never differs by more than one.
21 | */
22 | public int getDepth(TreeNode node) {
23 | if (node == null) return 0;
24 |
25 | int l = getDepth(node.left);
26 | int r = getDepth(node.right);
27 | if (Math.abs(l - r) > 1) result = false;
28 | return Math.max(l, r) + 1;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/tree/easy/DiameterOfBinaryTree.java:
--------------------------------------------------------------------------------
1 | package solution.tree.easy;
2 |
3 | import solution.tree.TreeNode;
4 |
5 | /**
6 | * @see Task 543
7 | */
8 | public class DiameterOfBinaryTree {
9 |
10 | int diameter = 0;
11 |
12 | public int diameterOfBinaryTree(TreeNode root) {
13 | calculate(root);
14 | return diameter;
15 | }
16 |
17 | private int calculate(TreeNode root) {
18 | if (root.left == null && root.right == null) return 0;
19 | int l = root.left == null ? 0 : calculate(root.left) + 1;
20 | int r = root.right == null ? 0 : calculate(root.right) + 1;
21 | if (l + r > diameter) diameter = l + r;
22 | return Math.max(l, r);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/tree/easy/InvertBinaryTree.java:
--------------------------------------------------------------------------------
1 | package solution.tree.easy;
2 |
3 | import solution.tree.TreeNode;
4 |
5 | /**
6 | * @see Task 226
7 | */
8 | public class InvertBinaryTree {
9 |
10 | public TreeNode invertTree(TreeNode root) {
11 | invertTreeNode(root);
12 | return root;
13 | }
14 |
15 | private void invertTreeNode(TreeNode node) {
16 | if (node == null) return;
17 |
18 | TreeNode tmp = node.left;
19 | node.left = node.right;
20 | node.right = tmp;
21 |
22 | invertTreeNode(node.left);
23 | invertTreeNode(node.right);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/tree/easy/MaximumDepthOfBinaryTree.java:
--------------------------------------------------------------------------------
1 | package solution.tree.easy;
2 |
3 | import solution.tree.TreeNode;
4 |
5 | /**
6 | * @see Task 104
7 | */
8 | public class MaximumDepthOfBinaryTree {
9 |
10 | public int maxDepth(TreeNode root) {
11 | if (root == null) return 0;
12 | return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/tree/easy/SameTree.java:
--------------------------------------------------------------------------------
1 | package solution.tree.easy;
2 |
3 | import solution.tree.TreeNode;
4 |
5 | /**
6 | * @see Task 100
7 | */
8 | public class SameTree {
9 | public boolean isSameTree(TreeNode p, TreeNode q) {
10 | if (p == null && q == null) return true;
11 | if (p == null || q == null) return false;
12 | if (p.val != q.val) return false;
13 | return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/tree/easy/SubtreeOfAnotherTree.java:
--------------------------------------------------------------------------------
1 | package solution.tree.easy;
2 |
3 | import solution.tree.TreeNode;
4 |
5 | /**
6 | * @see Task 572
7 | */
8 | public class SubtreeOfAnotherTree {
9 | public boolean isSubtree(TreeNode root, TreeNode subRoot) {
10 | if (root == null) return false;
11 | if (isSame(root, subRoot)) return true;
12 | return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
13 | }
14 |
15 | private boolean isSame(TreeNode rootNode, TreeNode subRootNode) {
16 | if (rootNode == null && subRootNode == null) return true;
17 | if (rootNode == null || subRootNode == null) return false;
18 |
19 | if (rootNode.val != subRootNode.val) return false;
20 |
21 | return isSame(rootNode.left, subRootNode.left) && isSame(rootNode.right, subRootNode.right);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/tree/medium/BinaryTreeLevelOrderTraversal.java:
--------------------------------------------------------------------------------
1 | package solution.tree.medium;
2 |
3 | import solution.tree.TreeNode;
4 |
5 | import java.util.LinkedList;
6 | import java.util.List;
7 | import java.util.Queue;
8 |
9 | /**
10 | * @see Task 102
11 | */
12 | public class BinaryTreeLevelOrderTraversal {
13 |
14 | /**
15 | * Основаная идея:
16 | * запомнить размер текущего уровня дерева (levelSize) и последовательно обработать все узлы этого уровня.
17 | * После этого перейти к следующему уровню и повторить процесс до тех пор, пока очередь не станет пустой.
18 | */
19 | public List> levelOrder(TreeNode root) {
20 | List> list = new LinkedList<>();
21 | if (root == null) return list;
22 |
23 | Queue q = new LinkedList<>();
24 | q.add(root);
25 | int levelSize = q.size();
26 | List level = new LinkedList<>();
27 | while (!q.isEmpty()) {
28 | TreeNode node = q.poll();
29 | level.add(node.val);
30 | if (node.left != null) q.add(node.left);
31 | if (node.right != null) q.add(node.right);
32 |
33 | levelSize--;
34 | if (levelSize == 0) {
35 | list.add(level);
36 | level = new LinkedList<>();
37 | levelSize = q.size();
38 | }
39 | }
40 | return list;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/tree/medium/BinaryTreeRightSideView.java:
--------------------------------------------------------------------------------
1 | package solution.tree.medium;
2 |
3 | import solution.tree.TreeNode;
4 |
5 | import java.util.ArrayList;
6 | import java.util.LinkedList;
7 | import java.util.List;
8 | import java.util.Queue;
9 |
10 | /**
11 | * @see Task 199
12 | */
13 | public class BinaryTreeRightSideView {
14 |
15 | /**
16 | * Основная идея:
17 | * сохранить размер текущей очереди (size), пройти через первые size элементов и сохранить всех детей в очередь.
18 | * При этом, при добавлении элементов в очередь, сначала добавляем правого ребенка.
19 | * Это позволяет гарантировать, что первым элементом во вложенном цикле будет самый правый элемент уровня.
20 | */
21 | public List rightSideView(TreeNode root) {
22 | List result = new ArrayList<>();
23 | if (root == null) return result;
24 | Queue q = new LinkedList<>();
25 | q.add(root);
26 | while (!q.isEmpty()) {
27 | int size = q.size();
28 | for (int i = 0; i < size; i++) {
29 | TreeNode node = q.poll();
30 | if (i == 0) result.add(node.val);
31 | if (node.right != null) q.add(node.right);
32 | if (node.left != null) q.add(node.left);
33 | }
34 | }
35 | return result;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/tree/medium/LowestCommonAncestorOfABinarySearchTree.java:
--------------------------------------------------------------------------------
1 | package solution.tree.medium;
2 |
3 | import solution.tree.TreeNode;
4 |
5 | /**
6 | * @see Task 235
7 | *
8 | * TODO Check again later
9 | */
10 | public class LowestCommonAncestorOfABinarySearchTree {
11 |
12 | /**
13 | * LCA Wiki
14 | *
15 | * The lowest common ancestor is defined between two nodes p and q as the lowest node in T
16 | * that has both p and q as descendants (where we allow a node to be a descendant of itself).
17 | */
18 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
19 | if (p.val > root.val && q.val > root.val) {
20 | return lowestCommonAncestor(root.right, p, q);
21 | } else if (p.val < root.val && q.val < root.val) {
22 | return lowestCommonAncestor(root.left, p, q);
23 | } else {
24 | return root;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/README.md:
--------------------------------------------------------------------------------
1 | # Two pointers
2 |
3 | The two pointers algorithm is a popular technique used in computer science and programming for solving various problems
4 | efficiently. It involves using **two pointers** that traverse a data structure simultaneously, usually from different
5 | starting points or at different speeds, to solve the problem at hand.
6 |
7 | The basic idea behind the two pointers algorithm is to reduce the time complexity of a problem by avoiding redundant
8 | computations. By using **two pointers**, we can often achieve a linear - _O(n)_ or sub-linear - _O(const * n)_ runtime
9 | complexity, compared to a naive
10 | approach that would require nested loops or multiple iterations.
11 |
12 | The two pointers are typically initialized to different positions in the data structure and then updated based on
13 | certain conditions. These conditions can be defined according to the requirements of the problem being solved. As the
14 | pointers move through the data structure, they narrow down the search space or perform specific operations until the
15 | desired result is obtained.
16 |
17 | The two pointers algorithm is commonly used for solving problems such as:
18 |
19 | 1. Array manipulation: For example, finding a pair of elements in an array that satisfies a specific condition, such as
20 | the
21 | sum being equal to a target value. The two pointers can start from the beginning and end of the array and move
22 | towards
23 | each other until the desired pair is found.
24 |
25 | 2. String manipulation: In problems involving strings, the two pointers can be used to compare characters or search for
26 | patterns. For instance, in palindrome-related problems, two pointers can start from the beginning and end of the
27 | string
28 | and check if the characters match.
29 |
30 | 3. Linked list traversal: When working with linked lists, two pointers can be employed to traverse the list at different
31 | speeds, allowing operations like cycle detection or finding the middle element efficiently.
32 |
33 | 4. Searching and sorting: The two pointers algorithm can also be utilized for searching or sorting problems. For
34 | instance,
35 | in binary search, two pointers can be used to define the search range and update them based on the comparison of the
36 | target element with the middle element.
37 |
38 | ## Example 1: Finding a pair of elements with a sum equal to a target in a sorted array.
39 |
40 | ```java
41 | public class TwoPointersExample {
42 | public static int[] findPairWithTargetSum(int[] nums, int targetSum) {
43 | int left = 0; // Left pointer
44 | int right = nums.length - 1; // Right pointer
45 |
46 | while (left < right) {
47 | int currentSum = nums[left] + nums[right];
48 |
49 | if (currentSum == targetSum) {
50 | return new int[]{nums[left], nums[right]}; // Pair found
51 | } else if (currentSum < targetSum) {
52 | left++; // Increase the left pointer to increase the sum
53 | } else {
54 | right--; // Decrease the right pointer to decrease the sum
55 | }
56 | }
57 |
58 | return new int[0]; // Pair not found
59 | }
60 |
61 | public static void main(String[] args) {
62 | int[] nums = {2, 5, 8, 12, 30};
63 | int targetSum = 20;
64 |
65 | int[] result = findPairWithTargetSum(nums, targetSum);
66 |
67 | if (result.length == 2) {
68 | System.out.println("Pair found: " + result[0] + ", " + result[1]);
69 | } else {
70 | System.out.println("Pair not found.");
71 | }
72 | }
73 | }
74 | ```
75 |
76 | In this example, using the Two Pointers algorithm, we are looking for a pair of elements in a sorted array whose sum is
77 | equal to a target value. We initialize the **left** pointer **left** to the start of the array and the **right** pointer right to
78 | the end of the array. Then, we compare the sum of the elements pointed to by **left** and **right** with targetSum. If the sum
79 | is equal to targetSum, we return the found pair. If the sum is less than targetSum, we increment **left** to increase the
80 | sum. If the sum is greater than targetSum, we decrement **right** to decrease the sum. The process continues until **left**
81 | becomes greater than or equal to **right** (indicating no pair is found) or until a pair with the sum targetSum is found.
82 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/easy/MinimumDifferenceBetweenHighestAndLowestOfKScores.java:
--------------------------------------------------------------------------------
1 | package solution.two_pointers.easy;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * @see Task 1984
7 | */
8 | public class MinimumDifferenceBetweenHighestAndLowestOfKScores {
9 |
10 | public int minimumDifference(int[] nums, int k) {
11 | if (k == 1) return 0;
12 |
13 | Arrays.sort(nums); // O(n * log(n))
14 |
15 | int min = Integer.MAX_VALUE;
16 | for (int i = 0; i < nums.length - k + 1; i++) {
17 | int diff = Math.abs(nums[i] - nums[i + k - 1]);
18 | min = Math.min(diff, min);
19 | }
20 |
21 | return min;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/easy/ReverseString.java:
--------------------------------------------------------------------------------
1 | package solution.two_pointers.easy;
2 |
3 | /**
4 | * @see Task 344
5 | */
6 | public class ReverseString {
7 | /**
8 | * Modify s in-place
9 | */
10 | public void reverseString(char[] s) {
11 | int l = 0;
12 | int r = s.length - 1;
13 | while (l <= r) {
14 | char tmp = s[l];
15 | s[l++] = s[r];
16 | s[r--] = tmp;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/easy/ValidPalindrome.java:
--------------------------------------------------------------------------------
1 | package solution.two_pointers.easy;
2 |
3 | /**
4 | * @see Task 125
5 | */
6 | public class ValidPalindrome {
7 |
8 | public boolean isPalindrome_1(String s) {
9 | char[] chars = s
10 | .toLowerCase()
11 | .trim()
12 | .replaceAll("[^a-zA-Z0-9]", "")
13 | .toCharArray();
14 |
15 | for (int left = 0, right = chars.length - 1; left < right; left++, right--) {
16 | if (chars[left] != chars[right]) return false;
17 | }
18 | return true;
19 | }
20 |
21 | public boolean isPalindrome_2(String s) {
22 | int i = 0;
23 | int j = s.length() - 1;
24 | while (i < j) {
25 | while (!Character.isLetterOrDigit(s.charAt(i)) && i < j) i++;
26 | while (!Character.isLetterOrDigit(s.charAt(j)) && j > i) j--;
27 |
28 | if (i > j || Character.toLowerCase(s.charAt(i)) != Character.toLowerCase(s.charAt(j))) return false;
29 |
30 | i++;
31 | j--;
32 | }
33 | return true;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/easy/ValidPalindrome2.java:
--------------------------------------------------------------------------------
1 | package solution.two_pointers.easy;
2 |
3 | /**
4 | * @see Task 680
5 | */
6 | public class ValidPalindrome2 {
7 |
8 | public boolean validPalindrome(String s) {
9 | return validator(s, 0, s.length() - 1, false);
10 | }
11 |
12 | boolean validator(String s, int i, int j, boolean deleted) {
13 | while (i < j) {
14 | if (s.charAt(i) == s.charAt(j)) {
15 | i += 1;
16 | j -= 1;
17 | } else {
18 | if (deleted) return false;
19 | return validator(s, i + 1, j, true) || validator(s, i, j - 1, true);
20 | }
21 | }
22 | return true;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/medium/ContainerWithMostWater.java:
--------------------------------------------------------------------------------
1 | package solution.two_pointers.medium;
2 |
3 | /**
4 | * @see Task 11
5 | */
6 | public class ContainerWithMostWater {
7 |
8 | public int maxArea(int[] height) {
9 | int result = 0;
10 | int l = 0;
11 | int r = height.length - 1;
12 | while (l < r) {
13 | int tmp = Math.min(height[l], height[r]) * (r - l);
14 | if (tmp > result) {
15 | result = tmp;
16 | }
17 | if (height[l] > height[r]) {
18 | r--;
19 | } else {
20 | l++;
21 | }
22 | }
23 | return result;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/medium/LinkedListCycle2.java:
--------------------------------------------------------------------------------
1 | package solution.two_pointers.medium;
2 |
3 | /**
4 | * @see solution.linked_list.easy.LinkedListCycle
5 | * @see Task 142
6 | */
7 | public class LinkedListCycle2 {
8 |
9 | public ListNode detectCycle(ListNode head) {
10 | if (head == null) return null;
11 | ListNode slow = head;
12 | ListNode fast = head;
13 |
14 | while (fast.next != null && fast.next.next != null) {
15 | fast = fast.next.next;
16 | slow = slow.next;
17 |
18 | if (fast == slow) {
19 | ListNode slow2 = head;
20 | while (slow2 != slow) {
21 | slow = slow.next;
22 | slow2 = slow2.next;
23 | }
24 | return slow;
25 | }
26 | }
27 | return null;
28 | }
29 |
30 | private static class ListNode {
31 | int val;
32 | ListNode next;
33 |
34 | ListNode(int x) {
35 | val = x;
36 | next = null;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/medium/RemoveDuplicatesFromSortedArray2.java:
--------------------------------------------------------------------------------
1 | package solution.two_pointers.medium;
2 |
3 | /**
4 | * @see Task 80
5 | */
6 | public class RemoveDuplicatesFromSortedArray2 {
7 |
8 | public int removeDuplicates(int[] nums) {
9 | markBadPositions(nums);
10 | int i = 0;
11 | while (i < nums.length && nums[i] != Integer.MIN_VALUE) i++;
12 |
13 | for (int j = i + 1; j < nums.length; j++) {
14 | if (nums[j] != Integer.MIN_VALUE) nums[i++] = nums[j];
15 | }
16 | return i;
17 | }
18 |
19 | /**
20 | * Если элемент повторяется больше 2х раз, то заменяем его на Integer.MIN_VALUE
21 | */
22 | private void markBadPositions(int[] nums) {
23 | int prev = Integer.MIN_VALUE;
24 | int prevCount = 0;
25 | int pos = 0;
26 |
27 | while (pos < nums.length) {
28 | if (nums[pos] != prev) {
29 | prev = nums[pos];
30 | prevCount = 1;
31 | } else {
32 | prevCount++;
33 | }
34 |
35 | if (prevCount > 2) nums[pos] = Integer.MIN_VALUE;
36 | pos++;
37 | }
38 | }
39 |
40 | public int removeDuplicates2(int[] nums) {
41 | if (nums.length == 0) return 0;
42 |
43 | int startIndex = 1;
44 | // count the time of duplicate numbers occurence
45 | int precCounter = 1;
46 |
47 | for (int i = 1; i < nums.length; i++) {
48 | if (nums[i] == nums[i - 1]) {
49 | if (precCounter < 2) {
50 | nums[startIndex++] = nums[i];
51 | }
52 | precCounter++;
53 | } else {
54 | precCounter = 1;
55 | nums[startIndex++] = nums[i];
56 | }
57 | }
58 | return startIndex;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/medium/RotateArray.java:
--------------------------------------------------------------------------------
1 | package solution.two_pointers.medium;
2 |
3 | /**
4 | * @see Task 189
5 | */
6 | public class RotateArray {
7 |
8 | public static void main(String[] args) {
9 | rotate(new int[]{1, 2, 3, 4, 5, 6, 7}, 3);
10 | }
11 |
12 | /**
13 | * With two pointer
14 | */
15 | public static void rotate(int[] nums, int k) {
16 | k = k % nums.length;
17 | if (k == 0) return;
18 | int l = 0, r = nums.length - 1;
19 | // in reverse order
20 | reverse(nums, l, r);
21 |
22 | // reverse first part from 0 to [k-1]
23 | l = 0;
24 | r = k - 1;
25 | reverse(nums, l, r);
26 |
27 | // reverse first part from k to the end
28 | l = k;
29 | r = nums.length - 1;
30 | reverse(nums, l, r);
31 |
32 | int a = 0;
33 | }
34 |
35 | private static void reverse(int[] nums, int l, int r) {
36 | while (l < r) {
37 | int tmp = nums[l];
38 | nums[l] = nums[r];
39 | nums[r] = tmp;
40 | l += 1;
41 | r -= 1;
42 | }
43 | }
44 |
45 | public void rotate2(int[] nums, int k) {
46 | if (k == 0) return;
47 | if (k > nums.length) k = k % nums.length;
48 |
49 | for (int i = 0; i < (nums.length / k) - 1; i++) {
50 | for (int j = 0; j < k; j++) {
51 | int i1 = nums.length - 1 - j - i * k;
52 | int i2 = nums.length - 1 - j - k * (i + 1);
53 | nums[i1] = nums[i1] ^ nums[i2];
54 | nums[i2] = nums[i1] ^ nums[i2];
55 | nums[i1] = nums[i1] ^ nums[i2];
56 | }
57 | }
58 |
59 | if (nums.length % k != 0) {
60 | for (int i = 0; i < nums.length - k - 1; i++) {
61 | nums[i] = nums[i + 1] ^ nums[i];
62 | nums[i + 1] = nums[i + 1] ^ nums[i];
63 | nums[i] = nums[i + 1] ^ nums[i];
64 | }
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/medium/Sum3.java:
--------------------------------------------------------------------------------
1 | package solution.two_pointers.medium;
2 |
3 | import java.util.*;
4 |
5 | /**
6 | * @see Task 15
7 | */
8 | public class Sum3 {
9 |
10 | public List> threeSum(int[] nums) {
11 | Arrays.sort(nums);
12 | Set> set = new HashSet<>();
13 |
14 | for (int i = 0; i < nums.length - 2; i++) {
15 | int l = i + 1;
16 | int r = nums.length - 1;
17 | while (l < r) {
18 | int sum = nums[i] + nums[l] + nums[r];
19 | if (sum == 0) {
20 | set.add(Arrays.asList(nums[i], nums[l], nums[r]));
21 | l++;
22 | r--;
23 | while (l < r && nums[l - 1] == nums[l]) l++;
24 | while (l < r && nums[r + 1] == nums[r]) r--;
25 | } else if (sum > 0) {
26 | r--;
27 | while (l < r && nums[r + 1] == nums[r]) r--;
28 | } else {
29 | l++;
30 | while (l < r && nums[l - 1] == nums[l]) l++;
31 | }
32 | }
33 | }
34 | return new ArrayList<>(set);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/algorithms/src/main/java/solution/two_pointers/medium/TwoSum2InputArrayIsSorted.java:
--------------------------------------------------------------------------------
1 | package solution.two_pointers.medium;
2 |
3 | /**
4 | * @see Task 167
5 | */
6 | public class TwoSum2InputArrayIsSorted {
7 | public int[] twoSum(int[] numbers, int target) {
8 | int left = 0;
9 | int right = numbers.length - 1;
10 | while (numbers[left] + numbers[right] != target) {
11 | if (numbers[left] + numbers[right] > target) {
12 | right--;
13 | } else {
14 | left++;
15 | }
16 | }
17 | return new int[]{left + 1, right + 1};
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/interview-questions/img/exceptions-hierarchy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Top4IkRu/java-interview/a26c8fdc50157108e12cc1239195b89234e4bfb4/interview-questions/img/exceptions-hierarchy.png
--------------------------------------------------------------------------------
/interview-questions/img/java-collection-hierarchy.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Top4IkRu/java-interview/a26c8fdc50157108e12cc1239195b89234e4bfb4/interview-questions/img/java-collection-hierarchy.webp
--------------------------------------------------------------------------------
/interview-questions/img/map-synchronization-process.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Top4IkRu/java-interview/a26c8fdc50157108e12cc1239195b89234e4bfb4/interview-questions/img/map-synchronization-process.jpg
--------------------------------------------------------------------------------
/interview-questions/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | interview-questions
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.springframework.boot
14 | spring-boot-starter-parent
15 | 2.7.10
16 |
17 |
18 |
19 |
20 | 11
21 | 11
22 | 1.16.3
23 | UTF-8
24 |
25 |
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-web
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-data-jdbc
34 |
35 |
36 | org.springframework.boot
37 | spring-boot-starter-test
38 | test
39 |
40 |
41 |
42 | org.apache.httpcomponents
43 | httpclient
44 |
45 |
46 | org.testcontainers
47 | junit-jupiter
48 | ${testcontainers.version}
49 | test
50 |
51 |
52 |
53 |
54 |
55 | org.springframework.boot
56 | spring-boot-maven-plugin
57 |
58 |
59 |
60 |
61 |
62 | central
63 | https://repo.maven.apache.org/maven2
64 |
65 |
66 |
--------------------------------------------------------------------------------
/interview-questions/src/main/java/concurrency/Volatile.java:
--------------------------------------------------------------------------------
1 | package concurrency;
2 |
3 | import java.util.concurrent.atomic.AtomicInteger;
4 | import java.util.function.Consumer;
5 |
6 | /**
7 | * Основная цель volatile - гарантировать, что чтение и запись значения переменной будут атомарными (неделимыми) операциями
8 | * и что изменения, внесенные одним потоком, будут видны другим потокам немедленно. Без использования volatile или
9 | * других механизмов синхронизации, изменения переменной, внесенные одним потоком, могут не отразиться в значениях,
10 | * видимых другим потокам.
11 | *
12 | * ATTENTION: concurrency.Volatile сам по себе не гарантирует атомарности или последовательности операций.
13 | *
14 | * Доп материалы:
15 | * 1. concurrency.Volatile
16 | * 2. Atomic
17 | */
18 |
19 | public class Volatile {
20 |
21 | private static int value = 0;
22 | private static volatile int volatileValue = value;
23 | private static final AtomicInteger atomicInteger = new AtomicInteger(value);
24 |
25 | public static void main(String[] args) throws InterruptedException {
26 | int repeatTime = 1000;
27 | int numberOfThreads = 100;
28 | int expect = repeatTime * numberOfThreads;
29 |
30 | doTheWorkInParallel(repeatTime, numberOfThreads, (index) -> value++);
31 | System.out.printf("Int value: expect = %d, actual = %d\n", expect, value);
32 |
33 | doTheWorkInParallel(repeatTime, numberOfThreads, (index) -> volatileValue++);
34 | System.out.printf("Int volatile value: expect = %d, actual = %d\n", expect, volatileValue);
35 |
36 | doTheWorkInParallel(repeatTime, numberOfThreads, (index) -> atomicInteger.incrementAndGet());
37 | System.out.printf("Atomic int value: expect = %d, actual = %d\n", expect, atomicInteger.get());
38 | }
39 |
40 |
41 | private static void doTheWorkInParallel(
42 | int repeatTime,
43 | int numberOfThreads,
44 | Consumer action
45 | ) throws InterruptedException {
46 |
47 | Runnable runnable = () -> {
48 | for (int i = 0; i < repeatTime; i++) action.accept(i);
49 | };
50 |
51 | Thread[] workers = new Thread[numberOfThreads];
52 | for (int i = 0; i < numberOfThreads; i++) {
53 | workers[i] = new Thread(runnable, String.valueOf(i));
54 | workers[i].start();
55 | }
56 |
57 | for (int j = 0; j < numberOfThreads; j++) workers[j].join();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/interview-questions/src/main/java/concurrency/concurrent-base.md:
--------------------------------------------------------------------------------
1 | # Оглавление
2 |
3 | ## Что такое потоки и процессы?
4 |
5 | ### Что такое процесс?
6 |
7 | Процесс в компьютерной системе представляет собой выполнение программы и является основной единицей для запуска
8 | программ. В Java, когда мы запускаем программу, на самом деле запускается процесс Java Virtual Machine (JVM), а основной
9 | поток, в котором выполняется основная функция программы, является одним из потоков в этом процессе, известным как
10 | основной поток.
11 | Представим это на примере. При запуске программы в операционной системе, например, в Windows, создается соответствующий
12 | процесс, который может быть наблюдаем в диспетчере задач. Этот процесс представляет собой выполнение программы
13 | (например, запуск .exe-файла).
14 | В случае Java-программы, процесс **JVM** (*Java Virtual Machine*) запускается, когда мы запускаем программу. Внутри
15 | процесса JVM создается основной поток, который выполняет основную функцию программы. Он может быть рассмотрен как
16 | основная нить исполнения внутри процесса JVM. Основной поток является точкой входа для выполнения программы и может
17 | порождать дополнительные потоки исполнения при необходимости.
18 | Таким образом, процесс в Java представляет собой выполнение программы, а основной поток является потоком исполнения
19 | внутри этого процесса, который выполняет основную функцию программы.
20 |
21 | ### Что такое поток?
22 |
23 | Потоки являются более мелкими единицами выполнения по сравнению с процессами. Процесс может порождать несколько потоков
24 | во время своего выполнения. В отличие от процессов, несколько потоков одного процесса совместно используют ресурсы кучи
25 | и области методов процесса. Однако каждый поток имеет свой собственный программный счетчик, стек виртуальной машины и
26 | локальный стек методов.
27 | При переключении между потоками нагрузка на систему намного меньше, чем при переключении между процессами. Поэтому
28 | потоки также называются легковесными процессами. Программы на Java, по своей сути, являются многопоточными программами,
29 | и мы можем использовать *Java Management Extensions* (**JMX**), чтобы увидеть, какие потоки присутствуют в обычной
30 | Java-программе.
31 | Вот пример кода, который позволяет нам получить информацию о потоках в Java:
32 |
33 | ```java
34 | import java.lang.management.ManagementFactory;
35 | import java.lang.management.ThreadInfo;
36 | import java.lang.management.ThreadMXBean;
37 |
38 | public class ThreadExample {
39 | public static void main(String[] args) {
40 | // Получаем экземпляр ThreadMXBean
41 | ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
42 |
43 | // Получаем информацию о потоках
44 | ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
45 |
46 | // Выводим информацию о каждом потоке
47 | for (ThreadInfo threadInfo : threadInfos) {
48 | System.out.println("Thread ID: " + threadInfo.getThreadId());
49 | System.out.println("Thread Name: " + threadInfo.getThreadName());
50 | System.out.println("Thread State: " + threadInfo.getThreadState());
51 | System.out.println("===========================");
52 | }
53 | }
54 | }
55 | ```
56 |
57 | В этом примере мы используем `ThreadMXBean`, который предоставляет методы для управления и мониторинга потоков в Java.
58 | Метод `dumpAllThreads(false, false)` возвращает информацию о всех потоках в системе. Затем мы выводим информацию о
59 | каждом потоке, такую как его идентификатор (**ID**), имя и состояние.
60 |
61 | Этот пример поможет нам лучше понять, какие потоки существуют в обычной Java-программе и как можно использовать Java
62 | Management Extensions для их анализа и мониторинга.
63 |
64 | ---
65 |
66 | ### Разница между синхронными и асинхронными вызовами
67 |
68 | 1. Синхронная обработка: после выполнения вызова происходит ожидание результата, и вызывающая сторона не продолжает
69 | выполнение до получения результата.
70 | 2. Асинхронная обработка: после выполнения вызова происходит немедленное возвращение, и
71 | вызывающая сторона может продолжить свою работу без ожидания результата возврата.
72 |
73 | ### Зачем использовать многопоточность?
74 |
75 | Поток можно рассматривать как легковесный процесс, являющийся наименьшей единицей выполнения программы. Переключение и
76 | планирование между потоками имеют гораздо меньшие накладные расходы по сравнению с процессами. С развитием многоядерных
77 | процессоров, несколько потоков могут выполняться одновременно, что позволяет снизить накладные расходы на переключение
78 | контекста потока. С точки зрения современных требований Интернета: Современные системы требуют миллионы или даже десятки
79 | миллионов параллельных операций, и многопоточное параллельное программирование является фундаментом для разработки
80 | высокопараллельных систем. Эффективное использование механизмов многопоточности может значительно повысить общий уровень
81 | параллелизма, возможности и производительность системы.
82 |
83 | ### Жизненный цикл потока
84 |
85 | Поток в Java может находиться в одном из следующих 6 различных состояний:
86 |
87 | 1. NEW - начальное состояние, когда поток создан, но метод `start()` ещё не вызван.
88 | 2. RUNNABLE - состояние выполнения, когда поток готов к выполнению и ожидает запуска.
89 | 3. BLOCKED - состояние блокировки, когда поток ожидает разблокировки ресурса или монитора.
90 | 4. WAITING - состояние ожидания, когда поток ожидает, пока другой поток выполнит определенные действия, такие как
91 | уведомление или прерывание.
92 | 5. TIME_WAITING - состояние ожидания с тайм-аутом, когда поток ожидает определенное время, после чего возвращается в
93 | RUNNABLE состояние.
94 | 6. TERMINATED - состояние завершения, когда выполнение потока завершено.
95 |
96 | 
97 |
98 | ### Пул потоков
99 |
100 | Пул потоков представляет собой набор ресурсов, который управляет группой потоков, позволяя ограничивать и управлять ими.
101 | Каждый пул потоков также предоставляет базовую статистику, такую как количество выполненных задач.
102 | Вот краткое описание преимуществ использования пулов потоков:
103 |
104 | 1. Экономия ресурсов: Пул потоков позволяет снизить расход ресурсов путем повторного использования созданных потоков,
105 | вместо создания и уничтожения потоков каждый раз при выполнении задачи. Это сокращает затраты на создание и
106 | уничтожение потоков.
107 | 2. Повышение отзывчивости: При поступлении задачи ее можно немедленно выполнить с использованием уже существующего
108 | потока из пула, вместо ожидания создания нового потока. Это улучшает отзывчивость системы.
109 | 3. Управляемость потоками: Потоки являются ценными ресурсами, и их неограниченное создание может привести к исчерпанию
110 | системных ресурсов и снижению стабильности системы. Использование пула потоков позволяет единообразно распределять,
111 | настраивать и мониторить потоки.
112 |
113 | Пул потоков обычно используется для выполнения нескольких независимых трудоемких задач. Без использования
114 | многопоточности задачи выполняются последовательно. Однако, при использовании пула потоков, несколько независимых задач
115 | могут выполняться параллельно, что повышает эффективность выполнения задач.
116 |
117 | ### Executor diagram
118 |
119 | 
--------------------------------------------------------------------------------
/interview-questions/src/main/java/concurrency/images/ExecutorDiagram.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Top4IkRu/java-interview/a26c8fdc50157108e12cc1239195b89234e4bfb4/interview-questions/src/main/java/concurrency/images/ExecutorDiagram.jpeg
--------------------------------------------------------------------------------
/interview-questions/src/main/java/concurrency/images/ThreadStatuses.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Top4IkRu/java-interview/a26c8fdc50157108e12cc1239195b89234e4bfb4/interview-questions/src/main/java/concurrency/images/ThreadStatuses.png
--------------------------------------------------------------------------------
/interview-questions/src/main/java/spring/TransactionService.java:
--------------------------------------------------------------------------------
1 | package spring;
2 |
3 | import org.springframework.transaction.TransactionStatus;
4 | import org.springframework.transaction.annotation.Propagation;
5 | import org.springframework.transaction.annotation.Transactional;
6 | import org.springframework.transaction.support.TransactionCallbackWithoutResult;
7 | import org.springframework.transaction.support.TransactionTemplate;
8 |
9 | public class TransactionService {
10 | private final TransactionTemplate transactionTemplate;
11 |
12 | public TransactionService(TransactionTemplate transactionTemplate) {
13 | this.transactionTemplate = transactionTemplate;
14 | }
15 |
16 | @Transactional
17 | public void withInternalTransaction() {
18 | int one = 1, two = 2;
19 | internalTransaction();
20 | System.out.println(one + two);
21 | transactionTemplate.execute(new TransactionCallbackWithoutResult() {
22 | @Override
23 | protected void doInTransactionWithoutResult(TransactionStatus status) {
24 | internalTransaction();
25 | }
26 | });
27 | }
28 |
29 | @Transactional(propagation = Propagation.REQUIRES_NEW)
30 | public void internalTransaction() {
31 | System.out.println("Internal transaction call");
32 | }
33 |
34 | @Transactional
35 | public void longTransaction() throws InterruptedException {
36 | System.out.println("Start long work.");
37 | Thread.sleep(10000);
38 | System.out.println("Work is completed.");
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tools.md:
--------------------------------------------------------------------------------
1 | # Tools
2 |
3 | ## Git
4 |
5 | `Git` is a must-learn tool that you will use every day, so you need to know what it is and also know the basic commands.
6 |
7 | `Git` is a version control system that allows you to keep track of changes that occur in a project. `Git` provides a
8 | secure and seamless way for multiple developers to work on the same project.
9 |
10 | 1. [Documentation](https://git-scm.com/book/en/v2)
11 | 2. [Step-by-step Git introduction guide](https://gitimmersion.com/index.html)
12 | 3. [CodeAcademy course](https://www.codecademy.com/learn/learn-git)
13 | 4. [Git cheat sheet](https://education.github.com/git-cheat-sheet-education.pdf)
14 |
15 | ## Docker
16 |
17 | `Docker` allows developers to package applications and their dependencies in an isolated container. This simplifies the
18 | deployment process and ensures that the application will run consistently on any system where `Docker` is installed.
19 |
20 | 1. [Step-by-step guide with labs](https://github.com/docker/labs)
21 | 2. [En Youtube full course](https://youtu.be/3c-iBn73dDE?si=ZR7JiGzdK1nSX9w5)
22 | 3. [Ru Youtube full course](https://youtu.be/n9uCgUzfeRQ?si=QllvUoDlAZ7aNXjm)
23 |
--------------------------------------------------------------------------------