I'm now resolving the #5 problem of Leetcode OJ, ZigZag Conversion. The codes below is my answer:
class Solution {
public:
string convert(string s, int nRows) {
int n = (int)s.size(), block_size = (nRows - 1);
if (n <= nRows || nRows == 1)
return s;
string re = "";
int len = nRows - 2 + nRows;
for (int left = len, right = 0, i = 0; i < nRows; ++i) {
bool is_left = false;
char current = 0;
int offset = 0;
while (i + offset <= n) {
if (!is_left) {
if (left != 0) {
current = s[i + offset];
re.push_back(current);
}
offset += left;
is_left = true;
} else {
if (right != 0) {
current = s[i + offset];
re.push_back(current);
}
offset += right;
is_left = false;
}
}
left -= 2;
right = len - left;
}
return re;
}
};
After my submission, the OJ replied: Submission Result: Wrong Answer. However, it also said that my codes' output is "ACB" and the expected answer is exactly same of "ACB".
Why the answer is wrong when the output and expected is same.
By the way, What's the compiler version of c++ of Leetcode? Sometime, the output of my g++ compiler is different from the leetcode's output.
From Leetcode forum:
Language Version Notes
C++ g++ 6.3
Related
I recently finished making an algorithm for a project I'm working on.
Briefly, a part of my project needs to fill a matrix, the requirements of how to do it are these:
- Fill the matrix in form of spiral, from the center.
- The size of the matrix must be dynamic, so the spiral can be large or small.
- Every two times a cell of the matrix is filled, //DO STUFF must be executed.
In the end, the code that I made works, it was my best effort and I am not able to optimize it more, it bothers me a bit having had to use so many ifs, and I was wondering if someone could take a look at my code to see if it is possible to optimize it further or some constructive comment (it works well, but it would be great if it was faster, since this algorithm will be executed several times in my project). Also so that other people can use it!
#include <stdio.h>
typedef unsigned short u16_t;
const u16_t size = 7; //<-- CHANGE HERE!!! just odd numbers and bigger than 3
const u16_t maxTimes = 2;
u16_t array_cont[size][size] = { 0 };
u16_t counter = 3, curr = 0;
u16_t endColumn = (size - 1) / 2, endRow = endColumn;
u16_t startColumn = endColumn + 1, startRow = endColumn + 1;
u16_t posLoop = 2, buffer = startColumn, i = 0;
void fillArray() {
if (curr < maxTimes) {
if (posLoop == 0) { //Top
for (i = buffer; i <= startColumn && curr < maxTimes; i++, curr++)
array_cont[endRow][i] = counter++;
if (curr == maxTimes) {
if (i <= startColumn) {
buffer = i;
} else {
buffer = endRow;
startColumn++;
posLoop++;
}
} else {
buffer = endRow;
startColumn++;
posLoop++;
fillArray();
}
} else if (posLoop == 1) { //Right
for (i = buffer; i <= startRow && curr < maxTimes; i++, curr++)
array_cont[i][startColumn] = counter++;
if (curr == maxTimes) {
if (i <= startRow) {
buffer = i;
} else {
buffer = startColumn;
startRow++;
posLoop++;
}
} else {
buffer = startColumn;
startRow++;
posLoop++;
fillArray();
}
} else if (posLoop == 2) { //Bottom
for (i = buffer; i >= endColumn && curr < maxTimes; i--, curr++)
array_cont[startRow][i] = counter++;
if (curr == maxTimes) {
if (i >= endColumn) {
buffer = i;
} else {
buffer = startRow;
endColumn--;
posLoop++;
}
} else {
buffer = startRow;
endColumn--;
posLoop++;
fillArray();
}
} else if (posLoop == 3) { //Left
for (i = buffer; i >= endRow && curr < maxTimes; i--, curr++)
array_cont[i][endColumn] = counter++;
if (curr == maxTimes) {
if (i >= endRow) {
buffer = i;
} else {
buffer = endColumn;
endRow--;
posLoop = 0;
}
} else {
buffer = endColumn;
endRow--;
posLoop = 0;
fillArray();
}
}
}
}
int main(void) {
array_cont[endColumn][endColumn] = 1;
array_cont[endColumn][endColumn + 1] = 2;
//DO STUFF
u16_t max = ((size * size) - 1) / maxTimes;
for (u16_t j = 0; j < max; j++) {
fillArray();
curr = 0;
//DO STUFF
}
//Demostration
for (u16_t x = 0; x < size; x++) {
for (u16_t y = 0; y < size; y++)
printf("%-4d ", array_cont[x][y]);
printf("\n");
}
return 0;
}
Notice that the numbers along the diagonal (1, 9, 25, 49) are the squares of the odd numbers. That's an important clue, since it suggests that the 1 in the center of the matrix should be treated as the end of a spiral.
From the end of each spiral, the x,y coordinates should be adjusted up and to the right by 1. Then the next layer of the spiral can be constructed by moving down, left, up, and right by the same amount.
For example, starting from the position of the 1, move up and to the right (to the position of the 9), and then form a loop with the following procedure:
move down, and place the 2
move down, and place the 3
move left, and place the 4
move left, and place the 5
etc.
Thus the code looks something like this:
int size = 7;
int matrix[size][size];
int dy[] = { 1, 0, -1, 0 };
int dx[] = { 0, -1, 0, 1 };
int directionCount = 4;
int ringCount = (size - 1) / 2;
int y = ringCount;
int x = ringCount;
int repeatCount = 0;
int value = 1;
matrix[y][x] = value++;
for (int ring = 0; ring < ringCount; ring++)
{
y--;
x++;
repeatCount += 2;
for (int direction = 0; direction < directionCount; direction++)
for (int repeat = 0; repeat < repeatCount; repeat++)
{
y += dy[direction];
x += dx[direction];
matrix[y][x] = value++;
}
}
I saw already many approaches for doing a spiral. All a basically drawing it, by following a path.
BUT, you can also come up with an analytical calculation formula for a spiral.
So, no recursion or iterative solution by following a path or such. We can directly calculate the indices in the matrix, if we have the running number.
I will start with the spiral in mathematical positive direction (counter clockwise) in a cartesian coordinate system. We will concentrate on X and Y coordinates.
I made a short Excel and derived some formulas from that. Here is a short picture:
From the requirements we know that the matrix will be quadratic. That makes things easier. A little bit trickier is, to get the matrix data symmetrical. But with some simple formulas, derived from the prictures, this is not really a problem.
And then we can calculate x and y coordinates with some simple statements. See the below example program with long variable names for better understanding. The code is made using some step by step approach to illustrate the implementation. Of course it can be made more compact easily. Anyway. Let's have a look.
#include <iostream>
#include <cmath>
#include <iomanip>
int main() {
// Show some example values
for (long step{}; step < 81; ++step) {
// Calculate result
const long roundedSquareRoot = std::lround(std::sqrt(step));
const long roundedSquare = roundedSquareRoot * roundedSquareRoot;
const long distance = std::abs(roundedSquare - step) - roundedSquareRoot;
const long rsrIsOdd = (roundedSquareRoot % 2);
const long x = (distance + roundedSquare - step - rsrIsOdd) / (rsrIsOdd ? -2 : 2);
const long y = (-distance + roundedSquare - step - rsrIsOdd) / (rsrIsOdd ? -2 : 2);
// Show ouput
std::cout << "Step:" << std::setw(4) << step << std::setw(3) << x << ' ' << std::setw(3) << y << '\n';
}
}
So, you see that we really have an analytical solution. Given any number we can calculate the x and y coordinate using a formula. Cool.
Getting indices in a matrix is just adding some offset.
With that gained know how, we can now easily calculate the complete matrix. And, since there is no runtime activity needed at all, we can let the compiler do the work. We will simply use constexpr functions for everything.
Then the compiler will create this matrix at compile time. At runtime, nothing will happen.
Please see a very compact solution:
#include <iostream>
#include <iomanip>
#include <array>
constexpr size_t MatrixSize = 15u;
using MyType = long;
static_assert(MatrixSize > 0 && MatrixSize%2, "Matrix size must be odd and > 0");
constexpr MyType MatrixHalf = MatrixSize / 2;
using Matrix = std::array<std::array<MyType, MatrixSize>, MatrixSize >;
// Some constexpr simple mathematical functions ------------------------------------------------------------------------------
// No need for <cmath>
constexpr MyType myAbs(MyType v) { return v < 0 ? -v : v; }
constexpr double mySqrtRecursive(double x, double c, double p) {return c == p? c: mySqrtRecursive(x, 0.5 * (c + x / c), c); }
constexpr MyType mySqrt(MyType x) {return (MyType)(mySqrtRecursive((double)x,(double)x,0.0)+0.5); }
// Main constexpr function will fill the matrix with a spiral pattern during compile time -------------------------------------
constexpr Matrix fillMatrix() {
Matrix matrix{};
for (int i{}; i < (MatrixSize * MatrixSize); ++i) {
const MyType rsr{ mySqrt(i) }, rs{ rsr * rsr }, d{ myAbs(rs - i) - rsr }, o{ rsr % 2 };
const size_t col{ (size_t)(MatrixHalf +((d + rs - i - o) / (o ? -2 : 2)))};
const size_t row{ (size_t)(MatrixHalf -((-d + rs - i - o) / (o ? -2 : 2)))};
matrix[row][col] = i;
}
return matrix;
}
// This is a compile time constant!
constexpr Matrix matrix = fillMatrix();
// All the above has been done during compile time! -----------------------------------------
int main() {
// Nothing to do. All has beend done at compile time already!
// The matrix is already filled with a spiral pattern
// Just output
for (const auto& row : matrix) {
for (const auto& col : row) std::cout << std::setw(5) << col << ' '; std::cout << '\n';
}
}
Different coordinate systems or other spiral direction can be adapted easily.
Happy coding.
I'm new to C++ and our teacher asked us to get a function that does the above title. So far I've got a function that converts a string to an integer, but I have no idea about how to modify it to make it work if the numbers in the string would represent a float.
int convert(char str[], int size) {
int number = 0;
for (int i = 0; i < size; ++i) {
number += (str[i] - 48)*pow(10, (size - i - 1));
}
return number;
}
If I run:
char myString[] = "12345";
convert(myString, 5);
I get:
12345
But if I run:
char myString[] = "123.45";
convert(myString, 5);
I get:
122845
How could I modify my program to work with floats too? I know convert function is meant to return an int so, should I use two more functions?
I was thinking about one that determinates if the string is inteded to be converted to an integer or a string, and the other that'll actually convert the string to a float.
Here is the function for doing so...
template<class T, class S>
T convert_string_to_number(S s)
{
auto result = T(0.l);
if (s.back() == L'F' || s.back() == L'f')
s = s.substr(0u, s.size() - 1u);
auto temp = s;
auto should_add = false;
if (!std::is_floating_point<T>::value)
{
should_add = temp.at(temp.find_first_of(L'.') + 1) >= '5';
temp.erase(temp.begin() + temp.find_first_of(L'.'), temp.end());
}
else if (temp.find_first_of(L'.') != S::npos)
temp.erase(temp.begin() + temp.find_first_of(L'.'));
for (int i = temp.size() - 1u; i >= 0; --i)
if (temp[i] >= L'0' && temp[i] <= L'9')
result += T(std::powl(10.l, temp.size() - i - 1.l) * (temp[i] - L'0'));
else
throw std::invalid_argument("Invalid numerical string!");
if (s.find(L'-') != S::npos)
result = -T(std::fabs(result));
if (s.find(L'.') != S::npos && std::is_floating_point<T>::value)
result /= T(std::powl(10.l, s.size() - s.find(L'.') - 1.l));
return std::is_floating_point<T>::value ? T(result) : T(result + T(should_add));
}
Just use it like you typically would...
auto some_number = convert_string_to_number<float>(myString);...
For the floating point part of the assignment: what about regular expressions? It is also kind of built-in functionality, but general purpose, not designed for your particular task, so I hope your teacher will be fine with this idea.
You can use the following regex: [+-]?([0-9]*[.])?[0-9]+ (I got it from this answer) to detect if provided string is a floating point number. Then you can modify the expression a little bit to capture the +/- signs and parts before/after the dot separator. Once you extract these features the task should be relatively simple.
Also please change your method signature to: float convert(const std::string& str).
Try this :
int convert(char str[], int size) {
int number = 0;
for (int i = 0; i < size; ++i) {
number += (str[i] - 48)*pow(10, (size - i - 1));
}
return number;
}
int pow10(int radix)
{
int r = 1;
for (int i = 0; i < radix; i++)
r *= 10;
return r;
}
float convert2float(char str[], int size) { //size =6
// convert to string_without_decimal
char str_without_decimal[10];
int c = 0;
for (int i = 0; i < size; i++)
{
if (str[i] >= 48 && str[i] <= 57) {
str_without_decimal[c] = str[i];
c++;
}
}
str_without_decimal[c] = '\0'; //str_without_decimal = "12345"
//adjust size if dot present or not. If no dot present => size = c
size = (size != c ?) size - 1 : size; //size = 5 = 6-1 since dot is present
//convert to decimal
int decimal = convert(str_without_decimal, size); //decimal = 12345
//get divisor
int i;
for (i = size; i >= 0; i--) {
if (str[i] == '.') break;
}
int divisor = pow10(size - i); //divisor = 10;
return (float)decimal/(float) divisor; // result = 12345 /10
}
int main()
{
char str[] = "1234.5";
float f = convert2float(str, 6);
cout << f << endl;
return 0;
}
I'm trying to solve this problem in C++:
"Given a sequence S of integers, find a number of increasing sequences I such that every two consecutive elements in I appear in S, but on the opposite sides of the first element of I."
This is the code I've developed:
#include<iostream>
#include<set>
#include<vector>
using namespace std;
struct Element {
long long height;
long long acc;
long long con;
};
bool fncomp(Element* lhs, Element* rhs) {
return lhs->height < rhs->height;
}
int solution(vector<int> &H) {
// set up
int N = (int)H.size();
if (N == 0 || N == 1) return N;
long long sol = 0;
// build trees
bool(*fn_pt)(Element*, Element*) = fncomp;
set<Element*, bool(*)(Element*, Element*)> rightTree(fn_pt), leftTree(fn_pt);
set<Element*, bool(*)(Element*, Element*)>::iterator ri, li;
for (int i = 0; i < N; i++) {
Element* e = new Element;
e->acc = 0;
e->con = 0;
e->height = H[i];
rightTree.insert(e);
}
//tree elements set up
ri = --rightTree.end();
Element* elem = *ri;
elem->con = 1;
elem->acc = 1;
while (elem->height > H[0]) {
Element* succ = elem;
ri--;
elem = *ri;
elem->con = 1;
elem->acc = succ->acc + 1;
}
rightTree.erase(ri);
elem->con = elem->acc;
leftTree.insert(elem);
sol += elem->acc;
// main loop
Element* pE = new Element;
for (int j = 1; j < (N - 1); j++) {
// bad case
if (H[j] < H[j - 1]) {
///////
Element* nE = new Element;
nE->height = H[j];
pE->height = H[j - 1];
rightTree.erase(nE);
leftTree.insert(nE);
///////
li = leftTree.lower_bound(pE);
long ltAcc = (*li)->acc;
li--;
///////
ri = rightTree.lower_bound(pE);
long rtAcc = 0;
if (ri != rightTree.end()) rtAcc = (*ri)->acc;
ri--;
///////
while (ri != (--rightTree.begin()) && (*ri)->height > H[j]) {
if (fncomp(*ri, *li)) {
(*li)->con = rtAcc + 1;
(*li)->acc = rtAcc + 1 + ltAcc;
ltAcc = (*li)->acc;
--li;
}
else {
(*ri)->con = ltAcc + 1;
(*ri)->acc = ltAcc + 1 + rtAcc;
rtAcc = (*ri)->acc;
--ri;
}
}
while ((*li)->height > H[j]) {
(*li)->con = rtAcc + 1;
(*li)->acc = rtAcc + 1 + ltAcc;
ltAcc = (*li)->acc;
--li;
}
(*li)->con = rtAcc + 1;
(*li)->acc = rtAcc + 1 + ltAcc;
sol += (*li)->acc;
}
// good case
else {
Element* nE = new Element;
nE->height = H[j];
ri = rightTree.upper_bound(nE);
li = leftTree.upper_bound(nE);
rightTree.erase(nE);
if (li == leftTree.end() && ri == rightTree.end()) {
nE->con = 1;
nE->acc = 1;
}
else if (li != leftTree.end() && ri == rightTree.end()) {
nE->con = 1;
nE->acc = 1 + (*li)->acc;
}
else if (li == leftTree.end() && ri != rightTree.end()) {
nE->con = (*ri)->acc + 1;
nE->acc = nE->con;
}
else {
nE->con = (*ri)->acc + 1;
nE->acc = nE->con + (*li)->acc;
}
leftTree.insert(nE);
sol += nE->acc;
}
}
// final step
li = leftTree.upper_bound(*rightTree.begin());
while (li != leftTree.end()) {
sol++;
li++;
}
sol++;
return (int)(sol % 1000000007);
}
int main(int argc, char* argv[]) {
vector<int> H = { 13, 2, 5 };
cout << "sol: " << solution(H) << endl;
system("pause");
}
The main function calls solution(vector<int> H). The point is, when the argument has the particular value of H = {13, 2, 5} the VC++ compiled program give an output value of 7 (which is the correct one), but the GNU g++ compiled program give an output value of 5 (also clang compiled program behave like this).
I'm using this website, among others, for testing different compilers
http://rextester.com/l/cpp_online_compiler_gcc
I've tried to figure out the reason for this wierd behaviour but didn't found any relevant info. Only one post treat a similar problem:
Different results VS C++ and GNU g++
and that's why I'm using long long types in the code, but the problem persists.
The problem was decrementing the start-of-sequence --rightTree.begin()
As I found VC++ and GNU g++ does not behave the same way on above operation. Here is the code that shows the difference, adapted from http://www.cplusplus.com/forum/general/84609/:
#include<iostream>
#include<set>
using namespace std;
struct Element {
long long height;
long long acc;
long long con;
};
bool fncomp(Element* lhs, Element* rhs) {
return lhs->height < rhs->height;
}
int main(){
bool(*fn_pt)(Element*, Element*) = fncomp;
set<Element*, bool(*)(Element*, Element*)> rightTree(fn_pt);
set<Element*, bool(*)(Element*, Element*)>::iterator ri;
ri = rightTree.begin();
--ri;
++ri;
if(ri == rightTree.begin()) cout << "it works!" << endl;
}
I'm posting this although much has already been posted about this question. I didn't want to post as an answer since it's not working. The answer to this post (Finding the rank of the Given string in list of all possible permutations with Duplicates) did not work for me.
So I tried this (which is a compilation of code I've plagiarized and my attempt to deal with repetitions). The non-repeating cases work fine. BOOKKEEPER generates 83863, not the desired 10743.
(The factorial function and letter counter array 'repeats' are working correctly. I didn't post to save space.)
while (pointer != length)
{
if (sortedWordChars[pointer] != wordArray[pointer])
{
// Swap the current character with the one after that
char temp = sortedWordChars[pointer];
sortedWordChars[pointer] = sortedWordChars[next];
sortedWordChars[next] = temp;
next++;
//For each position check how many characters left have duplicates,
//and use the logic that if you need to permute n things and if 'a' things
//are similar the number of permutations is n!/a!
int ct = repeats[(sortedWordChars[pointer]-64)];
// Increment the rank
if (ct>1) { //repeats?
System.out.println("repeating " + (sortedWordChars[pointer]-64));
//In case of repetition of any character use: (n-1)!/(times)!
//e.g. if there is 1 character which is repeating twice,
//x* (n-1)!/2!
int dividend = getFactorialIter(length - pointer - 1);
int divisor = getFactorialIter(ct);
int quo = dividend/divisor;
rank += quo;
} else {
rank += getFactorialIter(length - pointer - 1);
}
} else
{
pointer++;
next = pointer + 1;
}
}
Note: this answer is for 1-based rankings, as specified implicitly by example. Here's some Python that works at least for the two examples provided. The key fact is that suffixperms * ctr[y] // ctr[x] is the number of permutations whose first letter is y of the length-(i + 1) suffix of perm.
from collections import Counter
def rankperm(perm):
rank = 1
suffixperms = 1
ctr = Counter()
for i in range(len(perm)):
x = perm[((len(perm) - 1) - i)]
ctr[x] += 1
for y in ctr:
if (y < x):
rank += ((suffixperms * ctr[y]) // ctr[x])
suffixperms = ((suffixperms * (i + 1)) // ctr[x])
return rank
print(rankperm('QUESTION'))
print(rankperm('BOOKKEEPER'))
Java version:
public static long rankPerm(String perm) {
long rank = 1;
long suffixPermCount = 1;
java.util.Map<Character, Integer> charCounts =
new java.util.HashMap<Character, Integer>();
for (int i = perm.length() - 1; i > -1; i--) {
char x = perm.charAt(i);
int xCount = charCounts.containsKey(x) ? charCounts.get(x) + 1 : 1;
charCounts.put(x, xCount);
for (java.util.Map.Entry<Character, Integer> e : charCounts.entrySet()) {
if (e.getKey() < x) {
rank += suffixPermCount * e.getValue() / xCount;
}
}
suffixPermCount *= perm.length() - i;
suffixPermCount /= xCount;
}
return rank;
}
Unranking permutations:
from collections import Counter
def unrankperm(letters, rank):
ctr = Counter()
permcount = 1
for i in range(len(letters)):
x = letters[i]
ctr[x] += 1
permcount = (permcount * (i + 1)) // ctr[x]
# ctr is the histogram of letters
# permcount is the number of distinct perms of letters
perm = []
for i in range(len(letters)):
for x in sorted(ctr.keys()):
# suffixcount is the number of distinct perms that begin with x
suffixcount = permcount * ctr[x] // (len(letters) - i)
if rank <= suffixcount:
perm.append(x)
permcount = suffixcount
ctr[x] -= 1
if ctr[x] == 0:
del ctr[x]
break
rank -= suffixcount
return ''.join(perm)
If we use mathematics, the complexity will come down and will be able to find rank quicker. This will be particularly helpful for large strings.
(more details can be found here)
Suggest to programmatically define the approach shown here (screenshot attached below) given below)
I would say David post (the accepted answer) is super cool. However, I would like to improve it further for speed. The inner loop is trying to find inverse order pairs, and for each such inverse order, it tries to contribute to the increment of rank. If we use an ordered map structure (binary search tree or BST) in that place, we can simply do an inorder traversal from the first node (left-bottom) until it reaches the current character in the BST, rather than traversal for the whole map(BST). In C++, std::map is a perfect one for BST implementation. The following code reduces the necessary iterations in loop and removes the if check.
long long rankofword(string s)
{
long long rank = 1;
long long suffixPermCount = 1;
map<char, int> m;
int size = s.size();
for (int i = size - 1; i > -1; i--)
{
char x = s[i];
m[x]++;
for (auto it = m.begin(); it != m.find(x); it++)
rank += suffixPermCount * it->second / m[x];
suffixPermCount *= (size - i);
suffixPermCount /= m[x];
}
return rank;
}
#Dvaid Einstat, this was really helpful. It took me a WHILE to figure out what you were doing as I am still learning my first language(C#). I translated it into C# and figured that I'd give that solution as well since this listing helped me so much!
Thanks!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace CsharpVersion
{
class Program
{
//Takes in the word and checks to make sure that the word
//is between 1 and 25 charaters inclusive and only
//letters are used
static string readWord(string prompt, int high)
{
Regex rgx = new Regex("^[a-zA-Z]+$");
string word;
string result;
do
{
Console.WriteLine(prompt);
word = Console.ReadLine();
} while (word == "" | word.Length > high | rgx.IsMatch(word) == false);
result = word.ToUpper();
return result;
}
//Creates a sorted dictionary containing distinct letters
//initialized with 0 frequency
static SortedDictionary<char,int> Counter(string word)
{
char[] wordArray = word.ToCharArray();
int len = word.Length;
SortedDictionary<char,int> count = new SortedDictionary<char,int>();
foreach(char c in word)
{
if(count.ContainsKey(c))
{
}
else
{
count.Add(c, 0);
}
}
return count;
}
//Creates a factorial function
static int Factorial(int n)
{
if (n <= 1)
{
return 1;
}
else
{
return n * Factorial(n - 1);
}
}
//Ranks the word input if there are no repeated charaters
//in the word
static Int64 rankWord(char[] wordArray)
{
int n = wordArray.Length;
Int64 rank = 1;
//loops through the array of letters
for (int i = 0; i < n-1; i++)
{
int x=0;
//loops all letters after i and compares them for factorial calculation
for (int j = i+1; j<n ; j++)
{
if (wordArray[i] > wordArray[j])
{
x++;
}
}
rank = rank + x * (Factorial(n - i - 1));
}
return rank;
}
//Ranks the word input if there are repeated charaters
//in the word
static Int64 rankPerm(String word)
{
Int64 rank = 1;
Int64 suffixPermCount = 1;
SortedDictionary<char, int> counter = Counter(word);
for (int i = word.Length - 1; i > -1; i--)
{
char x = Convert.ToChar(word.Substring(i,1));
int xCount;
if(counter[x] != 0)
{
xCount = counter[x] + 1;
}
else
{
xCount = 1;
}
counter[x] = xCount;
foreach (KeyValuePair<char,int> e in counter)
{
if (e.Key < x)
{
rank += suffixPermCount * e.Value / xCount;
}
}
suffixPermCount *= word.Length - i;
suffixPermCount /= xCount;
}
return rank;
}
static void Main(string[] args)
{
Console.WriteLine("Type Exit to end the program.");
string prompt = "Please enter a word using only letters:";
const int MAX_VALUE = 25;
Int64 rank = new Int64();
string theWord;
do
{
theWord = readWord(prompt, MAX_VALUE);
char[] wordLetters = theWord.ToCharArray();
Array.Sort(wordLetters);
bool duplicate = false;
for(int i = 0; i< theWord.Length - 1; i++)
{
if(wordLetters[i] < wordLetters[i+1])
{
duplicate = true;
}
}
if(duplicate)
{
SortedDictionary<char, int> counter = Counter(theWord);
rank = rankPerm(theWord);
Console.WriteLine("\n" + theWord + " = " + rank);
}
else
{
char[] letters = theWord.ToCharArray();
rank = rankWord(letters);
Console.WriteLine("\n" + theWord + " = " + rank);
}
} while (theWord != "EXIT");
Console.WriteLine("\nPress enter to escape..");
Console.Read();
}
}
}
If there are k distinct characters, the i^th character repeated n_i times, then the total number of permutations is given by
(n_1 + n_2 + ..+ n_k)!
------------------------------------------------
n_1! n_2! ... n_k!
which is the multinomial coefficient.
Now we can use this to compute the rank of a given permutation as follows:
Consider the first character(leftmost). say it was the r^th one in the sorted order of characters.
Now if you replace the first character by any of the 1,2,3,..,(r-1)^th character and consider all possible permutations, each of these permutations will precede the given permutation. The total number can be computed using the above formula.
Once you compute the number for the first character, fix the first character, and repeat the same with the second character and so on.
Here's the C++ implementation to your question
#include<iostream>
using namespace std;
int fact(int f) {
if (f == 0) return 1;
if (f <= 2) return f;
return (f * fact(f - 1));
}
int solve(string s,int n) {
int ans = 1;
int arr[26] = {0};
int len = n - 1;
for (int i = 0; i < n; i++) {
s[i] = toupper(s[i]);
arr[s[i] - 'A']++;
}
for(int i = 0; i < n; i++) {
int temp = 0;
int x = 1;
char c = s[i];
for(int j = 0; j < c - 'A'; j++) temp += arr[j];
for (int j = 0; j < 26; j++) x = (x * fact(arr[j]));
arr[c - 'A']--;
ans = ans + (temp * ((fact(len)) / x));
len--;
}
return ans;
}
int main() {
int i,n;
string s;
cin>>s;
n=s.size();
cout << solve(s,n);
return 0;
}
Java version of unrank for a String:
public static String unrankperm(String letters, int rank) {
Map<Character, Integer> charCounts = new java.util.HashMap<>();
int permcount = 1;
for(int i = 0; i < letters.length(); i++) {
char x = letters.charAt(i);
int xCount = charCounts.containsKey(x) ? charCounts.get(x) + 1 : 1;
charCounts.put(x, xCount);
permcount = (permcount * (i + 1)) / xCount;
}
// charCounts is the histogram of letters
// permcount is the number of distinct perms of letters
StringBuilder perm = new StringBuilder();
for(int i = 0; i < letters.length(); i++) {
List<Character> sorted = new ArrayList<>(charCounts.keySet());
Collections.sort(sorted);
for(Character x : sorted) {
// suffixcount is the number of distinct perms that begin with x
Integer frequency = charCounts.get(x);
int suffixcount = permcount * frequency / (letters.length() - i);
if (rank <= suffixcount) {
perm.append(x);
permcount = suffixcount;
if(frequency == 1) {
charCounts.remove(x);
} else {
charCounts.put(x, frequency - 1);
}
break;
}
rank -= suffixcount;
}
}
return perm.toString();
}
See also n-th-permutation-algorithm-for-use-in-brute-force-bin-packaging-parallelization.
I need some help. I'm writing a code in C++ that will ultimately take a random string passed in, and it will do a break at every point in the string, and it will count the number of colors to the right and left of the break (r, b, and w). Here's the catch, the w can be either r or b when it breaks or when the strong passes it ultimately making it a hybrid. My problem is when the break is implemented and there is a w immediately to the left or right I can't get the program to go find the fist b or r. Can anyone help me?
#include <stdio.h>
#include "P2Library.h"
void doubleNecklace(char neck[], char doubleNeck[], int size);
int findMaxBeads(char neck2[], int size);
#define SIZE 7
void main(void)
{
char necklace[SIZE];
char necklace2[2 * SIZE];
int brk;
int maxBeads;
int leftI, rightI, leftCount = 0, rightCount=0, totalCount, maxCount = 0;
char leftColor, rightColor;
initNecklace(necklace, SIZE);
doubleNecklace(necklace, necklace2, SIZE);
maxBeads = findMaxBeads(necklace2, SIZE * 2);
checkAnswer(necklace, SIZE, maxBeads);
printf("The max number of beads is %d\n", maxBeads);
}
int findMaxBeads(char neck2[], int size)
{
int brk;
int maxBeads;
int leftI, rightI, leftCount = 0, rightCount=0, totalCount, maxCount = 0;
char leftColor, rightColor;
for(brk = 0; brk < 2 * SIZE - 1; brk++)
{
leftCount = rightCount = 0;
rightI = brk;
rightColor = neck2[rightI];
if(rightI == 'w')
{
while(rightI == 'w')
{
rightI++;
}
rightColor = neck2[rightI];
}
rightI = brk;
while(neck2[rightI] == rightColor || neck2[rightI] == 'w')
{
rightCount++;
rightI++;
}
if(brk > 0)
{
leftI = brk - 1;
leftColor = neck2[leftI];
if(leftI == 'w')
{
while(leftI == 'w')
{
leftI--;
}
leftColor = neck2[leftI];
}
leftI = brk - 1;
while(leftI >= 0 && neck2[leftI] == leftColor || neck2[leftI] == 'w')
{
leftCount++;
leftI--;
}
}
totalCount = leftCount + rightCount;
if(totalCount > maxCount)
{
maxCount = totalCount;
}
}
return maxCount;
}
void doubleNecklace(char neck[], char doubleNeck[], int size)
{
int i;
for(i = 0; i < size; i++)
{
doubleNeck[i] = neck[i];
doubleNeck[i+size] = neck[i];
}
}
I didn't study the code in detail, but something is not symmetric: in the for loop, the "left" code has an if but the "right" code doesn't. Maybe you should remove that -1 in the for condition and add it as an if for the "right" code:
for(brk = 0; brk < 2 * SIZE; brk++)
{
leftCount = rightCount = 0;
if (brk < 2 * SIZE - 1)
{
rightI = brk;
rightColor = neck2[rightI];
//...
}
if(brk > 0)
{
leftI = brk - 1;
leftColor = neck2[leftI];
//...
}
//...
Just guessing, though... :-/
Maybe you should even change those < for <=.