I am writing a backtracking algorithm, I think my writing is correct, but the output is wrong. I went to debug and found that the execution:When the program executes to this sentence in the for loop, sometimes it directly skips the following statement in the for loop.
Question is here:
Permutation Sequence
I have written a debugging environment, which can be run directly.
My answer is here:
class Solution {
public:
int index = 0, N, K;
string ans;
string getPermutation(int n, int k) {
N = n;
K = k;
string str;
backtrace(str, 0);
return ans;
}
void backtrace(string &str, int start) {
if (start == N) {
index++;
if (index == K) {
ans = str;
}
return;
}
for (int i = start; i < N; i++) {
if (index == K) {
return;
}
string temp = str; //For loop to this sentence will not execute the following statement
str += to_string(i + 1);
backtrace(str, i + 1);
str = temp;
}
}
};
int nn(int n) {
if (n == 1) {
return 1;
}
return nn(n - 1) * n;
}
int main() {
Solution so;
for (int i = 1; i <= nn(3); i++) {
cout << so.getPermutation(3, i) << endl;
}
system("pause");
}
I’m not sure if it’s the c++ problem or mine, or it might be my algorithm,but I’ve checked it many times.
My previous thinking was wrong,#Igor Tandetnik remended me . This problem requires a bit of mathematical skills or it will time out. Thanks for your help #john and #Igor Tandetnik.
My finally code is here:
class Solution {
private:
vector<int> hash;
vector<int> factorial;
bool flag = true;
void dfs(int cur, int n, int &k, string &ret, int &cnt, string path){
if(cur == n){
ret = path;
flag = false;
return;
}
int temp = factorial[n-cur-1];
for(int i=0; i<n; i++){
if(hash[i] && flag){
if(temp < k ){
k = k - temp;
continue;
}
path.push_back(i+1+'0');
hash[i] = 0;
dfs(cur+1,n,k,ret,cnt,path);
hash[i] = 1;
path.pop_back();
}
}
}
public:
string getPermutation(int n, int k) {
//calculate the factorial
if(n == 1) return "1";
factorial.resize(n);
factorial[0] = 1;
factorial[1] = 1;
if(n > 2){
for(int i=2; i<n; i++){
factorial[i] = i * factorial[i-1];
}
}
string ret;
string path;
hash.resize(n,1);
int cnt = 0;
dfs(0,n,k,ret,cnt,path);
return ret;
}
};
Assuming n = 4, k = 17, we can know that the 17th permutation is [3,4,1,2]. In order to find it, we need to do pruning at key nodes. How to judge? As shown in the figure, when we start the search, we visit the purple node "1", and notice that if we continue to visit (deep search) at this time, it is actually meaningless, because there are at most 3 from this node! =6 full permutations and combinations, and what we are looking for is the 17th, 6<17, so we prun directly; visit the purple node "2", the same thing can be seen, you need pruning at this node; visit the purple node "3" ", now that the conditions are met, 6> 5, you need to search down. (Note here that a simple counting technique is that when a node needs to be pruned, we need to update the value of k, k = k-the node corresponds to the factorial number).
Author: edward_wang
Related
I am writing code for Leetcode problem 38. Count and Say. It doesn't pass the cases, so I add some cout to debug. Please tell me is there a normal way to debug nested for loop, where should I add the cout expression. I don't want to know how to modify the code to pass the cases.
Here is my code:
class Solution {
public:
string countAndSay(int n) {
string cur("1");
while (--n) {
string tmp = cur;
string next;
for (int i = 0; i < tmp.size();) {
cout << "i:" << i << endl;
int count = 1;
for (int j = i + 1; j < tmp.size(); j++) {
if (tmp[j] != tmp[0]) {
break;
}
count++;
}
cout << "count:" << count << endl;
next += std::to_string(count) + tmp[0];
cout << "cur:" << cur << endl;
i += count;
}
cur = next;
cout << n << cur << endl;
}
return cur;
}
};
You're gonna have to use a debugger for that, and step by step go through your algorithm to find the bugs. It's hard to debug someone else's algorithm.
This'll pass through:
#include <string>
struct Solution {
static const std::string countAndSay(int n) {
if (not n) {
return "";
}
std::string res = "1";
while (--n) {
std::string curr = "";
for (int index = 0; index < res.size(); index++) {
int count = 1;
while ((index + 1 < res.size()) and (res[index] == res[index + 1])) {
count++;
index++;
}
curr += std::to_string(count) + res[index];
}
res = curr;
}
return res;
}
};
Java Solutions
class Solution {
public String countAndSay(int n) {
if (n == 1)
return "1";
String prev = countAndSay(n - 1);
StringBuilder str = new StringBuilder();
int i = 0;
while (i < prev.length()) {
char curr = prev.charAt(i);
int j = 0;
while (i + j < prev.length() && prev.charAt(i + j) == curr)
j++;
str.append(j);
str.append(curr);
i += j;
}
return str.toString();
}
}
Here is one of LeetCode's solutions using regex:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Solution {
public String countAndSay(int n) {
String currSeq = "1";
// Pattern to match the repetitive digits
String regexPattern = "(.)\\1*";
Pattern pattern = Pattern.compile(regexPattern);
for (int i = 1; i < n; ++i) {
Matcher m = pattern.matcher(currSeq);
StringBuffer nextSeq = new StringBuffer();
// each group contains identical and adjacent digits
while (m.find()) {
nextSeq.append(m.group().length() + String.valueOf(m.group().charAt(0)));
}
// prepare for the next iteration
currSeq = nextSeq.toString();
}
return currSeq;
}
}
and here's another LeetCode's solution also using Sliding Window:
class Solution {
public String countAndSay(int n) {
LinkedList<Integer> prevSeq = new LinkedList<Integer>();
prevSeq.add(1);
// Using -1 as the delimiter
prevSeq.add(-1);
List<Integer> finalSeq = this.nextSequence(n, prevSeq);
StringBuffer seqStr = new StringBuffer();
for (Integer digit : finalSeq) {
seqStr.append(String.valueOf(digit));
}
return seqStr.toString();
}
protected LinkedList<Integer> nextSequence(int n, LinkedList<Integer> prevSeq) {
if (n <= 1) {
// remove the delimiter before return
prevSeq.pollLast();
return prevSeq;
}
LinkedList<Integer> nextSeq = new LinkedList<Integer>();
Integer prevDigit = null;
Integer digitCnt = 0;
for (Integer digit : prevSeq) {
if (prevDigit == null) {
prevDigit = digit;
digitCnt += 1;
} else if (digit == prevDigit) {
// in the middle of the sub-sequence
digitCnt += 1;
} else {
// end of a sub-sequence
nextSeq.add(digitCnt);
nextSeq.add(prevDigit);
// reset for the next sub-sequence
prevDigit = digit;
digitCnt = 1;
}
}
// add the delimiter for the next recursion
nextSeq.add(-1);
return this.nextSequence(n - 1, nextSeq);
}
}
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis1, 2 in there.
I'm trying to answer a question on leetcode https://leetcode.com/problems/palindromic-substrings/. I know the passing solution is an O(N^2) solution with dynamic programming. All the solutions I've seen have used a bottom-up approach. I tried to use a top-down approach and I thought I also accomplished O(N^2) but the online judge is giving me time limit exceeded error at the final test case which made me unsure if my implementation is indeed O(N^2). Can someone please tell me the correct big O of the below code?
bool dfs(string s, int start, int end, string curWord, int &count, unordered_map<string, int> &map)
{
if (start >= end)
{
return true;
}
string st = to_string(start) + " , " + to_string(end);
if (map.find(st) != map.end())
return map[st];
if (s[start] == s[end] && dfs(s, start + 1, end - 1, curWord, count, map))
{
count++;
map[st] = true;
}
else
{
map[st] = false;
}
return map[st];
}
int countSubstrings(string s)
{
string word = "";
int count = 0;
unordered_map<string, int> map;
for (int i = 0; i < s.length(); i++)
{
for (int j = s.length() - 1; j > i; j--)
{
dfs(s, i, j, word, count, map);
}
}
return count + s.length();
}
Given an array of integers and a number k, write a function that returns true if given array can be divided into pairs such that sum of every pair is divisible by k.
This code is producing correct results for all test cases except one I cannot find the glitch in it.
#include <bits/stdc++.h>
using namespace std;
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int arr[n];
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
int k;
cin >> k;
int flag[n] = {0};
int p = 0;
int q = 0;
if (n % 2 != 0) {
cout << "False" << endl;
} else {
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if ((arr[i] + arr[j]) % k == 0 && flag[j] == 0) {
p = 1;
flag[j] = 1;
}
}
if (p == 0) {
q = 1;
cout << "False" << endl;
break;
}
}
if (q == 0) {
cout << "True" << endl;
}
}
}
return 0;
}
One of the big sources of bugs in code is messy code. So how do we clean up code? We modularize it. This means breaking up the code so that each portion of the code does one job well. Let's see what that looks like.
Function to check if something is divisible by k:
bool isDivisible(int number, int divisor) {
return number % divisor == 0;
}
Function to check all pairs:
The logic is as follows:
Take the first number in the list; call in n0.
For every remaining number n1, check if that plus the first number is divisible by k
When we find n1 such that n0 + n1 is divisible by k,
a. If the remaining numbers left over can also be split into divisible pairs, return true
b. Otherwise, continue searching
4.If we've searched through all the numbers, return false.
bool pairsDivisible(int* nums, int count, int k) {
if(count == 0) return true;
if(count % 2 != 0) return false; // count must be even
// 1.
int n0 = nums[0];
// 2.
for(int i = 1; i < count; i++) {
int n1 = nums[i];
// 3.
if(isDivisible(n0 + n1, k)) {
// Move the ith number so it's now nums[1]
std::swap(nums[1], nums[i]);
if(pairsDivisible(nums + 2, count - 2, k)) {
return true; // 3.a
} else {
// Reset the array
std::swap(nums[1], nums[i]);
}
}
}
return false;
}
I was solving the following question from Facebook Hacker Cup:
Since you crave state-of-the-art technology, you've just purchased a phone with a great new feature: autocomplete! Your phone's version of autocomplete has some pros and cons. On the one hand, it's very cautious. It only autocompletes a word when it knows exactly what you're trying to write. On the other hand, you have to teach it every word you want to use.
You have N distinct words that you'd like to send in a text message in order. Before sending each word, you add it to your phone's dictionary. Then, you write the smallest non-empty prefix of the word necessary for your phone to autocomplete the word. This prefix must either be the whole word, or a prefix which is not a prefix of any other word yet in the dictionary.
What's the minimum number of letters you must type to send all N words?
I am implementing a trie for this as follows:
struct trie {
int ct;
vector<trie*> child;
trie() {
ct = 0;
for(int i = 0; i < 26; i++) {
child.push_back(nullptr);
}
}
~trie() {
//cerr << "called\n";
for(int i = 0; i < 26; i++) {
delete child[i];
}
child.clear();
}
};
void add(trie* t, const string &str, int i) {
//ct++;
int index = str[i] - 'a';
if(t->child[index] == nullptr) {
t->child[index] = new trie();
}
t->child[index]->ct++;
i++;
if(i != str.length()) {
add(t->child[index], str, i);
}
}
int getL(trie* t, const string &str, int i) {
if(i == str.length()) {
return i;
}
int index = str[i] - 'a';
if(t->child[index]->ct == 1) {
return i + 1;
}
else {
return getL(t->child[index], str, i + 1);
}
}
int solve() {
int n;
cin >> n;
string s;
//cin >> s;
int i;
trie* root = new trie();
int ans = 0;
for(i = 0; i < n; i++) {
cin >> s;
cerr << "READ " << s << '\n';
add(root, s, 0);
cerr << "DONE ADD\n";
ans += getL(root, s, 0);
}
//int ans = 0;
delete (root);
return ans;
}
However I seem to be getting Segmentation fault(Core Dumped) error which I understand means that I am accessing an invalid memory location however I cannot seem to figure out where it is the case in my code. Any help would be appreciated.
I'm trying to solve an algorithm for extracting a subsequence from an array. It should display the longest subsequence of prime numbers. I have written the whole algorithm but I still get an infinite cycle and I can't figure out where and why. I'm incrementing both indices and modifying the first index at the end, but it is still not working. Thanks a lot !!!
P.S: citire reads the array, prim detects if a number is prime or composed, afisare displays the subsequence and detSecv determines the longest subsequence.
#include <iostream>
#include <math.h>
using namespace std;
void citireSecv(int &n,int x[50])
{
cout<<"Da n: ";
cin>>n;
for(int i=1;i<=n;i++)
{
cout<<"Da un nr: ";
cin>>x[i];
}
}
int prim(int n)
{
int d=2;
while(d<=sqrt(n) && n%d!=0)
{
if(d==2)
d=3;
else
d=d+2;
}
if(d>sqrt(n)) return 1;
else return 0;
}
void afisare(int n,int x[50],int st,int f)
{
for(int i=st;i<=f;i++)
cout<<x[i]<<" ";
}
void detSecv(int n,int x[100],int &st,int &f)
{
st=1; f=0;
int i=1,j;
while(i<=n-1)
{
while(i<=n-1)
{
if(prim(x[i])==0 && prim(x[i+1])==0) i++;
}
j=i+1;
while(j<=n-1)
if(prim(x[j])==0 && prim(x[j+1])==0) j++;
if((j-i) > (f-st))
{
st=i;
f=j;
}
i=j+1;
}
}
int main()
{
int n,x[100],st,f;
citireSecv(n,x);
detSecv(n,x,st,f);
afisare(n,x,st,f);
return 0;
}
Input data:
n=2
First number is: 5
Second number is: 7
Probably just one of many issues with that code:
while(i<=n-1)
{
if(prim(x[i])==0 && prim(x[i+1])==0) i++;
}
j=i+1;
while(j<=n-1)
if(prim(x[j])==0 && prim(x[j+1])==0) j++;
There are two potential infinite loops here. If the conditions in the while don't return true on the first iteration, i (or j) will never get incremented, and you will have your infinite loop. You should almost always increment such variables outside of any conditions.
With a slight change in your code, you make it work, and one thing, you don't need to start array with index 1. you can always start with index zero.
for(int i=1;i<=n;i++)
{
cout<<"Da un nr: ";
cin>>x[i];
}
try to check for a case when no prime subsequence is found, while printing.
void detSecv(int n, int *x, int &start, int &end)
{
start = -1;
end = -1;
int i=0,j;
while(i < n) {
if(prim(x[i])) {
j = i + 1;
while(j < n)
if(prim(x[j])) j++;
else break;
} else {
i++;
continue;
}
if((j-i) > (end - start)) {
start = i;
end = j-1;
}
i=j+1;
}
}
This is a better way to verify if a number is prime or not
bool IsPrime(int number) {
int primeStep = 2;
double stepLimit = sqrt(number);
while(primeStep <= stepLimit)
{
if(number % primeStep == 0)
return false;
primeStep += 1;
}
return true;
}
And nou you can apply that function for each number in your array, and if it's prime , you add it in a new array like this:
void detSecv(int numberOfItems,int *arrayOfNumbers)
{
int arrayOfPrimeNumbers[50] = {};
int index = 0;
for(int i = 0; i < numberOfItems; i++)
{
if(IsPrime(arrayOfNumbers[i])){
arrayOfPrimeNumbers[index] = arrayOfNumbers[i];
index += 1;
}
}
int secondIndex = 0;
while(arrayOfPrimeNumbers[secondIndex] != 0)
{
cout << arrayOfPrimeNumbers[secondIndex] << " ";
secondIndex += 1;
}
}