首页 > 其他分享 >A Pattern to Solve Backtracking Problems

A Pattern to Solve Backtracking Problems

时间:2023-12-14 22:37:14浏览次数:47  
标签:return idx nums int Pattern backtrack vector Solve Backtracking

The backtracking solutions of most leetcode-problems have a similar pattern. Let's take a look on it.

Subset

1. Recursion (Backtrack) - Time complexity is O(2^n), and the depth of recursion is O(n).

class Solution {
public:
    vector<vector<int>> ret;
    vector<int> sub;
    int n;
    vector<vector<int>> subsets(vector<int>& nums) 
    {
        n = nums.size();
        backtrack(nums, 0);
        return ret;
    }
    
    void backtrack(vector<int>& nums, int idx)
    {
        ret.emplace_back(sub);
        for (int i = idx; i < n; ++i)
        {
            sub.emplace_back(nums[i]);
            backtrack(nums, i + 1);
            sub.pop_back();
        }
    }
};

2. Iteration - Time complexity is still O(2^n), while space complexity is O(1).

For example, if nums = [1, 2, 3], then the changing process of subs is:

init  : {[]}
x = 1 : {[], [1]}
x = 2 : {[], [1], [2], [1, 2]}
x = 3 : {[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]}

Our code:

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> subs = {{}};
        for (int x : nums)
        {
            int n = subs.size();
            for (int i = 0; i < n; i++)
            {
                subs.emplace_back(subs[i]);
                subs.back().emplace_back(x);
            }
        }
        return subs;
    }
};

3. bitmap - Here the time complexity is O(2^N * N).

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) 
    {
        int n = nums.size();
        int total = 1 << n;
        vector<vector<int>> subs(total);
        for (int i = 0; i < total; ++i)
        {
            for (int j = 0; j < n; ++j)
                if ((i >> j) & 1) subs[i].emplace_back(nums[j]);
        }
        return subs;
    }
};

Subset II

1. Backtrack (recursion) - It's similar to "Subset" above.

class Solution {
public:
    int n;
    vector<vector<int>> ret;
    vector<int> sub;
    vector<vector<int>> subsetsWithDup(vector<int>& nums) 
    {
        sort(nums.begin(), nums.end());
        n = nums.size();
        backtrack(nums, 0);
        return ret;
    }
    
    void backtrack(vector<int> &nums, int idx)
    {
        ret.emplace_back(sub);
        for (int i = idx; i < n; ++i)
        {
            if (i > idx && nums[i] == nums[i - 1]) continue;
            sub.emplace_back(nums[i]);
            backtrack(nums, i + 1);
            sub.pop_back();
        }
    }
};

2. Iteration

It's a little similar to "Subset - Iteration" above, but not totally. See this explanation.

For "Interation Solution" of Subset, in the internal loop, we traverse all elements in the subs. Here we can not do so, since there are duplicate numbers.

As the figure shown above, if we still traverse all elements of subs, then we will add duplicate subsets into subs (the black ones). We need to fix this issue.

When we meet the duplicate number, such as second 2 above, we should not traverse all elements of subs. We just need to traverse the newest added ones (the orange elements in 3rd line).

Here we use variable start to store start-position of the newest elements.

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> subs = {{}};
        int size = nums.size();
        int start = subs.size();
        for (int i = 0; i < size; ++i)
        {
            int n = subs.size();
            for (int j = 0; j < n; ++j)
            {
                if ((i > 0 && nums[i] == nums[i - 1]) && j < start)
                    continue;
                subs.emplace_back(subs[j]);
                subs.back().emplace_back(nums[i]);
            }
            start = n;
        }
        return subs;
    }
};

Permutations

1. Backtrack

  • We allocate a buffer seq, to store each permutation of nums.
  • For each position of seq[idx], we try to put every numbers nums[i] on it (unless nums[i] have been used) .
  • Note that in the for-loop of backtrack function, we do not start at idx, while start at 0.
    • Why is it different from "Subset"? From the perspective of consequence, Subset has 2^n different states, while permutation has n! different states. The actual reason is that here each number must occur at least once in seq, while the situation in Subset is not.
class Solution {
public:
    vector<vector<int>> ret;
    vector<int> seq;
    bool used[6] = {0};
    int n;
    vector<vector<int>> permute(vector<int>& nums) {
        n = nums.size();
        seq.resize(n);
        backtrack(nums, 0);
        return ret;
    }

    void backtrack(vector<int> &nums, int idx)
    {
        if (idx >= n) 
        {
            ret.emplace_back(seq);
            return;
        }
        // here we do not start from idx
        // for position seq[idx], we try to put each number on it
        for (int i = 0; i < n; ++i)
        {
            if (used[i]) continue;
            seq[idx] = nums[i], used[i] = true;
            backtrack(nums, idx + 1);
            used[i] = false;
        }      
    }
};

Permutation II

1. Backtrack

There are duplicate number, hence we need a little modification on the solution of "Permutations".

See the if-branch, we add a new skip condition (i > 0 && nums[i] == nums[i - 1] && used[i - 1]) .

For example, if input [1a, 1b, a]

seq           used       idx    comment
[1a]          [1 0 0]     0     
[1a 1b]       [1 1 0]     1     (this can not happend, step back)
[1b]          [0 1 0]     0     
[1b 1a]       [1 1 0]     1     (this can happen)
[1b 1a 2a]    [1 1 1]     2     (add seq into result)

Thus, we can also change the condition into (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) . It will put 1a on the 1st position in above example.

class Solution {
public:
    int n;
    vector<int> seq;
    vector<vector<int>> res;
    bool used[8] = {false};
    vector<vector<int>> permuteUnique(vector<int>& nums) 
    {
        sort(nums.begin(), nums.end());
        n = nums.size();
        seq.resize(n);
        backtrack(nums, 0);
        return res;
    }
    void backtrack(vector<int> &nums, int idx)
    {
        if (idx >= n)
        {
            res.emplace_back(seq);
            return;
        }
        for (int i = 0; i < n; ++i)
        {
            if (used[i] || (i > 0 && nums[i] == nums[i - 1] && used[i - 1])) continue;
            seq[idx] = nums[i], used[i] = true;
            backtrack(nums, idx + 1);
            used[i] = false;
        }
    }
};

Combination Sum

1. Backtracking

class Solution {
public:
    vector<vector<int>> res;
    vector<int> seq;
    int n, target;
    vector<vector<int>> combinationSum(vector<int>& nums, int target) {
        n = nums.size(), this->target = target;
        backtrack(nums, 0, 0);
        return res;
    }
    void backtrack(vector<int> &nums, int idx, int cur)
    {
        if (cur > target) return;
        if (cur == target)
        {
            res.emplace_back(seq);
            return;
        }
        for (int i = idx; i < n; ++i)
        {
            seq.emplace_back(nums[i]);
            backtrack(nums, i, cur + nums[i]);
            seq.pop_back();
        }
    }
};

Combination Sum II

1. Backtracking

  • Sort the nums
  • If we meet the same value, then skip it. (See the if-branch below. )
class Solution {
public:
    vector<vector<int>> res;
    vector<int> seq;
    int n, target;
    vector<vector<int>> combinationSum2(vector<int>& nums, int target) 
    {
        sort(nums.begin(), nums.end());
        n = nums.size(), this->target = target;
        backtrack(nums, 0, 0);
        return res;
    }
    void backtrack(vector<int> &nums, int idx, int cur)
    {
        if (cur > target) return;
        if (cur == target)
        {
            res.emplace_back(seq);
            return;
        }
        for (int i = idx; i < n; ++i)
        {
            if (i > idx && nums[i] == nums[i - 1]) continue;
            seq.emplace_back(nums[i]);
            backtrack(nums, i + 1 , cur + nums[i]);
            seq.pop_back();
        }
    }
};

Palindrome Partitioning

1. Backtracking

Time complexity is O(n * 2^n), since for each letter range from 0 to n-1, we have two choices (split it or not), and for each choice, we need to check whether if it is palindrome in O(n) time.

class Solution {
public:
    vector<vector<string>> res;
    vector<string> buf;
    int n;
    vector<vector<string>> partition(string s) 
    {
        n = s.length();
        backtrack(s, 0);
        return res;
    }
    
    void backtrack(string &s, int idx)
    {
        if (idx >= n)
        {
            res.emplace_back(buf);
            return;
        }
        for (int i = idx; i < n; ++i)
        {
            if (check(s, idx, i))
            {
                buf.emplace_back(s.substr(idx, i - idx + 1));
                backtrack(s, i + 1);
                buf.pop_back();
            }
        }
    }
    bool check(string &s, int start, int end)
    {
        while (start < end)
        {
            if (s[start] != s[end]) return false;
            start++, end--;
        }
        return true;
    }
};

2. Dynamic Programming Optimization

We can pre-process for each postion pair <i, j>, store the result whether if s[i - j] is palindrome in array dp. Hence we can optimize check() method above into O(1) time.

Are the time complexity of this solution O(2^n) ? The answer is NO. See the internal function call s.substr, which need O(n) time. Hence the time complexity here is still O(n * 2 ^ n).

class Solution {
public:
    vector<vector<string>> res;
    vector<string> buf;
    vector<vector<bool>> dp;
    int n;
    vector<vector<string>> partition(string s) {
        n = s.length();
        dp.resize(n, vector<bool>(n, true)); // an empty string is always palindrome
        for (int i = n - 1; i >= 0; --i)
        {
            dp[i][i] = true; 
            for (int j = i + 1; j < n; ++j)
                dp[i][j] = s[i] == s[j] && dp[i + 1][j - 1];
        }
        backtrack(s, 0);
        return res;
    }
    
    void backtrack(string &s, int idx)
    {
        if (idx >= n)
        {
            res.emplace_back(buf);
            return;
        }
        for (int i = idx; i < n; ++i)
        {
            if (dp[idx][i])
            {
                buf.emplace_back(s.substr(idx, i - idx + 1));
                backtrack(s, i + 1);
                buf.pop_back();
            }
        }
    }
};

// dp[i, j] = dp[i+1, j-1] && s[i] == s[j] (j > i)

3. Memor Search

Based on the "backtracking" solution above, we just change the check method into:

unordered_map<int, unordered_map<int, bool>> table;
bool check(string &s, int start, int end)
{
    if (start >= end) return true;
    if (table.count(start) && table[start].count(end)) return table[start][end];
    return table[start][end] = (s[start] == s[end]) && check(s, start + 1, end - 1);
}

N-Queens

1. Backtracking (Recursion)

We assume that each queen is on different rows, and pos[i] denote her column-index of the board. i.e. <i, pos[i]> means the i-th queen is on i-th row, pos[i]-th column.

class Solution {
public:
    vector<vector<string>> res;
    vector<int> pos;
    int n;
    vector<vector<string>> solveNQueens(int n) 
    {
        this->n = n;
        pos.resize(n, -1);
        backtrack(0);
        return res;
    }
    
    void backtrack(int idx)
    {
        if (idx >= n)
        {
            res.emplace_back(generate(pos));
            return;
        }
        for (int i = 0; i < n; ++i)
        {
            pos[idx] = i;
            if (check(idx)) backtrack(idx + 1); // pay attention to this idx + 1
        }
    }
    
    bool check(int idx)
    {
        for (int i = 0; i < idx; ++i)
            if (pos[idx] == pos[i] || idx - i == abs(pos[idx] - pos[i]))
                return false;
        return true;
    }
    
    vector<string> generate(vector<int> &pos)
    {
        vector<string> ret(n, string(n, '.'));
        for (int i = 0; i < n; i++)
            ret[i][pos[i]] = 'Q';
        return move(ret);
    }
};

2. Iteration

class Solution {
public:
    vector<vector<string>> res;
    vector<int> pos;
    vector<vector<string>> solveNQueens(int n) 
    {
        pos.resize(n, -1);
        int cur = 0;
        while (cur >= 0)
        {
            while (pos[cur] < n)
            {
                if (++pos[cur] >= n) break; // for current queen, try every column
                if (check(cur))
                {
                    if (cur < n - 1) ++cur; // not a completed solution
                    else if (cur == n - 1)
                    {
                        res.emplace_back(generate(pos, n));
                        break;
                    }
                }
            }
            pos[cur] = -1, cur--;
        }
        return res;
    }
    
    bool check(int idx)
    {
        for (int i = 0; i < idx; ++i)
            if (pos[idx] == pos[i] || idx - i == abs(pos[idx] - pos[i]))
                return false;
        return true;
    }
    
    vector<string> generate(vector<int> &pos, int n)
    {
        vector<string> ret(n, string(n, '.'));
        for (int i = 0; i < n; i++)
            ret[i][pos[i]] = 'Q';
        return move(ret);
    }
};

N-Queens II

1. Iteration

It's an easy problem if we have solve the "N-Queens" with iteration solution.

class Solution {
public:
    int totalNQueens(int n) {
        vector<int> pos(n, -1);
        int cur = 0, res = 0;
        while (cur >= 0)
        {
            while (pos[cur] < n)
            {
                if (++pos[cur] >= n) break;
                if (check(pos, cur))
                {
                    if (cur < n - 1) ++cur;
                    else
                    {
                        ++res;
                        break;
                    }
                    
                }
            }
            pos[cur--] = -1;
        }
        return res;
    }
    bool check(vector<int> &pos, int idx)
    {
        for (int i = 0; i < idx; ++i)
            if (pos[i] == -1 || pos[i] == pos[idx] || idx - i == abs(pos[idx] - pos[i]))
                return false;
        return true;
    }
};

2. backtracking

class Solution {
public:
    vector<int> pos;
    int n, res;
    int totalNQueens(int n) 
    {
        pos.resize(n, -1);
        this->n = n, this->res = 0;
        backtrack(0);
        return res;
    }
    
    void backtrack(int idx)
    {
        if (idx >= n)
        {
            res += 1;
            return;
        }
        for (int i = 0; i < n; ++i)
        {
            pos[idx] = i;
            if (check(idx)) backtrack(idx + 1);
        }
    }
    
    bool check(int idx)
    {
        if (idx >= n) return true;
        for (int i = 0; i < idx; ++i)
            if (pos[i] == pos[idx] || abs(pos[i] - pos[idx]) == idx - i) return false;
        return true;
    }
};

Summary

We can see that the backtracking (recursion) pattern is similar in these problem.

vector<vector<int>> res;
vector<int> cur;
vector<vector<int>> solution()
{
    backtrack(..., 0);
    return res;
}
backtrack(..., int idx)
{
    if cur is satisfied with some conditions
    {
        // add current values into final result, and return
    }
    for (i = idx; i < n; i++)      // or for (i = 0; i < n; i++)
    {
        cur.push_back(value of i)  // try each possible value on current position idx, or cur[idx] = i
        if (cur is possible)       // if cur[idx]/cur.back() maybe a possible solution
            backtrack(..., i + 1)  // try next one based on current state, or backtrack(..., idx + 1)
        cur.pop_back()             // pop the value we have tried, or reset cur[idx]
    }
}

And there are two issues if we used this code template.

For the 1st issue, please note that, in the for-loop in backtrack, most of times we start from i = idx, while sometimes we start from i = 0 (e.g. the "Permutations" problem and "Permutations II" problem) .

How can we distinguish these two cases? A simple way is that:

  • Start from i = idx when the state space is O(2^n) (or equivalent exponential space).
  • Start from i = 0 when the state space is O(n!) .

The 2nd issue is whether to use backtrack(idx + 1) or backtrack(i + 1).

  • In some cases, we use backtrack(i + 1).
  • In "N-Queens" and "Permutations" problem, we use backtrack(idx + 1).

Why? This depends on what is the definition of "next possible value".

  • For "Subset", "Combination Sum" and "Palindrome Partition", the next posibble value is nums[i + 1] or s[i + 1], we try to put it into the current state. Here backtrack(j) means try nums[j] or s[j].
  • However, for the "N-Queens" (and "Permutations"), the position pos[idx], we want to try all the column-index on postion pos[idx]. Therefore, if pos[0, ..., idx] is a possible solution, we should continue to try on pos[idx + 1]. In "N-Queen", backtrack(j) means we try to put j-th queen on column-index range from 0 to n-1.
  • The most distinct (and essential) difference between these two kind of problems is that, a solution of first one is non-fixed length, while the second one is fixed-length. And the argument idx of backtrack(idx) have different meanings.

For these two issues, please learn how to distinguish them via passing these homework:

Combinations

This problem is O(n!) state space.

class Solution {
public:
    vector<vector<int>> res;
    vector<int> seq;
    vector<vector<int>> combine(int n, int k) 
    {
        seq.resize(k, -1);
        backtrack(0, n, k);
        return res;
    }
    void backtrack(int idx, int n, int k)
    {
        if (idx >= k)
        {
            res.emplace_back(seq);
            return;
        }
        for (int i = 1; i <= n; ++i)  // O(n!) state space
        {
            if (idx > 0 && i <= seq[idx - 1]) continue; // the combination pair require increasing order
            seq[idx] = i;
            backtrack(idx + 1, n, k); // try next position, fixed-length
            seq[idx] = -1;
        }
    }
};

Combination Sum III

The solution of this problem is fixed-length, and it has O(9!) state space.

class Solution {
public:
    vector<vector<int>> res;
    vector<int> seq;
    vector<vector<int>> combinationSum3(int k, int n) 
    {
        seq.resize(k, 0);
        backtrack(0, 0, k, n);
        return res;
    }
    
    void backtrack(int idx, int cur, int k, int n)
    {
        if (idx >= k)
        {
            if (cur == n) res.emplace_back(seq);
            return;
        }
        for (int i = 1; i <= 9; ++i)
        {
            if (idx > 0 && i <= seq[idx - 1]) continue;  // the pairs require increasing order
            seq[idx] = i;
            backtrack(idx + 1, cur + i, k, n);
            seq[idx] = 0;
        }
    }
};

Generate Parentheses

It is totally backtracking template problem, since

  • each solution is in fixed-length 2n, and
  • each position of a solution, has 2 possible values '(' and ')' .
class Solution {
public:
    vector<string> res;
    string seq;
    vector<string> generateParenthesis(int n) {
        seq.resize(n << 1, ' ');
        backtrack(0, n);
        return res;
    }
    
    void backtrack(int idx, int n)
    {
        if (idx >= (n << 1))
        {
            if (check(seq)) res.emplace_back(seq);
            return;
        }
        static const char values[2] = {'(', ')'};
        for (char val : values)
        {
            seq[idx] = val;
            backtrack(idx + 1, n);
            seq[idx] = ' ';
        }
    }
    bool check(string &s)
    {
        int cnt = 0;
        for (char x : s)
        {
            cnt += x == '(', cnt -= x == ')';
            if (cnt < 0) return false;
        }
        return cnt == 0;
    }
};

Phone Number

Features of this problem: it is fixed-length, and has O(2^n) state space.

class Solution {
public:
    const string letters[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    int n;
    string seq;
    vector<string> res;
    vector<string> letterCombinations(string digits) 
    {
        n = digits.size();
        if (n == 0) return res;
        
        seq.resize(n, ' ');
        backtrack(digits, 0);
        return res;
    }
    
    void backtrack(string &digits, int idx)
    {
        if (idx >= n)
        {
            res.emplace_back(seq);
            return;
        }
        for (char x : letters[digits[idx] - '0'])
        {
            seq[idx] = x;
            backtrack(digits, idx + 1);
            seq[idx] = ' ';
        }
    }
};

Additive Number

class Solution {
public:
    vector<string> buf;
    bool ret = false;
    int n;
    bool isAdditiveNumber(string s) 
    {
        n = s.length();
        backtrack(s, 0);
        return ret;
    }
    void backtrack(string &s, int idx)
    {
        if (ret) return;
        if (buf.size() >= 3)
        {
            if (!checkBuffer()) return;
            if (idx >= n)
            {
                ret = true;
                return;
            }
        }
        for (int i = idx; i < n; ++i)
        {
            buf.emplace_back(s.substr(idx, i - idx + 1));
            /* the solution for this problem is not fixed-length */
            backtrack(s, i + 1);
            buf.pop_back();
        }
    }
    
    bool checkBuffer()
    {
        int n = buf.size();
        
        string &a = buf[n - 3], &b = buf[n - 2], &c = buf[n - 1];
        
        if (a.length() > 1 && a[0] == '0' || 
            b.length() > 1 && b[0] == '0' || 
            c.length() > 1 && c[0] == '0') return false;
        return bigIntegerAdd(a, b) == c;
    }
    
    string bigIntegerAdd(const string &a, const string &b)
    {
        int alen = a.length(), blen = b.length();
        string res(max(alen, blen) + 1, '0');
        int i = alen - 1, j = blen - 1, val = 0, carry = 0;
        int ptr = res.length() - 1;
        while (i >= 0 || j >= 0)
        {
            val = carry;
            if (i >= 0) val += (a[i--] - '0');
            if (j >= 0) val += (b[j--] - '0');
            carry = (val >= 10);
            val %= 10;
            res[ptr--] = val + '0';
        }
        if (carry) res[ptr--] = 1 + '0';
        if (res[0] == '0' && res.length() > 1) res.erase(res.begin());
        return res;
    }
};

标签:return,idx,nums,int,Pattern,backtrack,vector,Solve,Backtracking
From: https://www.cnblogs.com/sinkinben/p/17902281.html

相关文章

  • Cannot resolve symbol 'Resource'
    扩展JSR-250注解@Resource理解JSR系列注解JSR(JavaSpecificationRequests)是Java平台标准化进程中的一种技术规范,而JSR注解是其中一部分重要的内容。按照JSR的分类以及注解语义的不同,可以将JSR注解分为不同的系列,主要有以下几个系列:JSR-175:这个JSR是JavaSE5引入的,是Java......
  • [JMeter] Apache Jmeter导入jmx压测脚本时,报错CannotResolveClassException: xxx
    1问题描述Jmeter导入jmx压测脚本时,报错CannotResolveClassException:xxxJMeterVersion:5.5JDK:8报错的关键信息:kg.apc.jmeter.vizualizers.CorrectedResultCollectorcom.thoughtworks.xstream.converters.ConversionException可见:缺少相关依赖包。2解......
  • 设计模式--观察者模式(Observer Pattern)
    Observer模式观察者模式(ObserverPattern)是一种行为设计模式,它定义了对象之间的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。观察者模式主要包含以下几个角色:Subject(主题):也被称为Observable,它是被观察的对象。当它的状态发生改变时,会通知......
  • SpringBoot Resolved [org.springframework.web.multipart.support.MissingServletRe
    SpringBootResolved[org.springframework.web.multipart.support.MissingServletRequestPartException:Requiredrequestpart'file'isnotpresent]IDEA报错信息这个错误主要主要是指后端通过@RequestParam("file")注解标注的MultipartFile参数并没有获取到文件参数为n......
  • 论文:FEED-FORWARD NETWORKS WITH ATTENTION CAN SOLVE SOME LONG-TERM MEMORY PROBLEM
    题目:FEED-FORWARDNETWORKSWITHATTENTIONCANSOLVESOMELONG-TERMMEMORYPROBLEMS”(Raffel和Ellis,2016,p.1)“带有注意力的前馈网络可以解决一些长期记忆问题”(Raffel和Ellis,2016,p.1)(pdf)这篇论文提出了一种适用于前馈神经网络的简化注意力模型,并展示了......
  • Spring MVC学习随笔-第一个Spring MVC程序(父子项目结构、Tomcat配置、ViewResolver)
    学习视频:孙哥说SpringMVC:结合Thymeleaf,重塑你的MVC世界!|前所未有的Web开发探索之旅第二章、第一个SpringMVC程序的开发2.1开发版本JDK1.8+Maven3.6+IDEA2021+SpringFramework5.1.4Tomcat8.5.29MySQL5.7.18按照父子项目的结构,管理和创建项目,创建一个空Project作为父项......
  • (Python)基于对称点模式(Symmetrized Dot Pattern,SDP)的多元、多通道、多传感器信号融合
    对称点模式(SymmetrizedDotPattern,SDP)算法可将复杂时间序列以散点的形式清晰映射在极坐标图中,可以使原始时域信号通过图形化的方式提高可视化能力。因为极坐标图像的特殊性,多元、多通道、多传感器信号信息可通过SDP方法融合在有限区域中。适用于多元、多通道、多传感器信号的融合......
  • [951] Understanding the pattern of "(.*?)" in Python's re package
    InPython'sregularexpressions, (.*?)isacapturinggroupwithanon-greedyquantifier. Let'sbreakdownthecomponents:(and ):Parenthesesareusedtocreateacapturinggroup.Thisallowsustocaptureaportionofthematchedtext..*?:......
  • Microservice- Resiliency patterns: Circuit Breaker Pattern
    Theretrypatternworkswellforcoveringtransientfailures,butifwedon’tknow howlongtheproblemwilllast,wemayendupputtingahighloadondependentserviceswithinfiniteretries.Let’slookatasmarterversionoftheretrypatternthat bre......
  • Microservice- Resiliency patterns: Retry Pattern
    RetryPatternTransientfaultsoccurwhenamomentarylossofservicefunctionalityself-corrects. TheretrypatterningRPCenablesustoretryafailedcallautomaticallyandthusis perfectfortransientfaultssuchasthese:Instantnetworkfailures......