简体   繁体   English

为什么我的哈希程序无法通过测试

[英]Why does my hashing program fail the tests

Task:任务:
To register in the system, each resident must come up with a password.要在系统中注册,每个居民都必须提供一个密码。 The password consists of letters of the Latin alphabet (uppercase and lowercase), as well as numbers from 0 to 9, that is, it is possible to use 62 characters in total.密码由拉丁字母(大写和小写)以及从0到9的数字组成,即总共可以使用62个字符。 The password length is from 5 to 20 characters.密码长度为 5 到 20 个字符。 The password is stored in the database in encrypted form, encryption is carried out according to the following algorithm:密码以加密形式存储在数据库中,按照以下算法进行加密:

  1. The number b of uppercase Latin letters is counted.计算大写拉丁字母的数量 b。 For each uppercase letter character in the password, a cyclic shift to the right by bb characters is performed (for example, if b=3, then the D character is converted to the G character, the Y character to the B character).对于密码中的每个大写字母字符,循环右移 bb 个字符(例如,如果 b=3,则 D 字符转换为 G 字符,Y 字符转换为 B 字符)。
  2. Similarly, for each lowercase character in the password, a cyclic shift to the right is performed by m characters, where m is the number of lowercase letters in the password.类似地,对于密码中的每个小写字符,循环向右移动 m 个字符,其中 m 是密码中小写字母的数量。

To quickly search for users in the database, a hash function is calculated for each encrypted password using the following algorithm:为了在数据库中快速搜索用户,使用以下算法为每个加密密码计算 hash function:

  1. All 62 characters are ordered, numbers come first, then lowercase letters, then uppercase letters.所有 62 个字符都是有序的,数字在前,然后是小写字母,然后是大写字母。
  2. Each character is assigned a code - the number of the character in this sequence, starting from 0. Thus, the digit codes match their values, the lowercase letter code a-10, b-11, etc.每个字符都分配有一个代码 - 此序列中字符的编号,从 0 开始。因此,数字代码匹配它们的值,小写字母代码 a-10、b-11 等。
  3. All codes are summed up, and the remainder of the resulting sum s is found from dividing by the numbers p and q.将所有代码相加,并通过除以数字 p 和 q 找到所得总和 s 的余数。 The resulting pair of numbers (s mod p,s mod q) will be the value of the hash function.生成的一对数字 (s mod p,s mod q) 将是 hash function 的值。

A hash function is considered good if collisions rarely occur, that is, the values of the function match for different passwords.如果很少发生冲突,则认为 hash function 是好的,即 function 的值匹配不同的密码。

John came up with a new password.约翰想出了一个新密码。 At the same time, there are already nn passwords in the database, and I would like to avoid collisions.同时数据库里已经有nn个密码了,希望避免冲突。 Will John succeed?约翰会成功吗?

Input data输入数据

The first line contains a string representing John's password.第一行包含一个表示 John 密码的字符串。 The second line contains an integer n – the number of passwords in the database.第二行包含一个 integer n - 数据库中的密码数量。 The third line contains integers p and q.第三行包含整数 p 和 q。 The following lines store passwords in unencrypted form.以下行以未加密的形式存储密码。

Output data Output数据

An integer is the number of passwords whose hash function matches the hash function of John's password. An integer is the number of passwords whose hash function matches the hash function of John's password.

Sample Input:样本输入:
AabB1cd AabB1cd
5 5
13 17 13 17
Nik143pasw尼克143pasw
qeAom1 qeAom1
q1w2e3r4t q1w2e3r4t
aBoba2012 aBoba2012
N33iEj N33iEj

Sample Output:样品 Output:
2 2

Note:笔记:
Passwords that match John's hash function are highlighted.与 John 的 hash function 匹配的密码会突出显示。

Processing of John's password: After cyclic shift: CefD1gh (uppercase letters are shifted by 2, lowercase by 4) The sum of the character codes is 38+14+15+39+1+16+17=140 The hash function is equal to (10,4) John的密码的处理:循环移位后:CefD1gh(大写字母移位2,小写字母移位4)字符代码之和为38+14+15+39+1+16+17=140 hash ZC1C425268E68385D1AB5074C17A9等于(10,4)

My Programm:我的程序:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    string pas;
    cin >> pas;
    int small = 0, big = 0;
    for (int i = 0; i < pas.length(); i++)
    {
        if (pas[i] >= 'A' && pas[i] <= 'Z')big++;
        if (pas[i] >= 'a' && pas[i] <= 'z')small++;
    }
    for (int i = 0; i < pas.length(); i++)
    {
        if (pas[i] + big >= 'A' && pas[i] + big <= 'Z') pas[i] = pas[i] + big;
        else if (pas[i] >= 'A' && pas[i] <= 'Z') {
            int tempVar = big;
            while (tempVar > 0) {
                if (pas[i] == 'Z') {
                    pas[i] = 'A';
                    tempVar = tempVar - 1;
                }
                tempVar = tempVar - 1;
                pas[i] = pas[i] + 1;
            }
        }
    }
    for (int i = 0; i < pas.length(); i++)
    {
        if (pas[i] + small >= 'a' && pas[i] + small <= 'z') pas[i] = pas[i] + small;
        else if (pas[i] >= 'a' && pas[i] <= 'z') {
            int tempVar = small;
            while (tempVar > 0) {
                if (pas[i] == 'z') {
                    pas[i] = 'a';
                    tempVar = tempVar - 1;
                }
                pas[i] = pas[i] + 1;
                tempVar = tempVar - 1;
            }
        }
    }
    int hash = 0;
    for (int i = 0; i < pas.length(); i++) {
        if ('0' <= pas[i] && '9' >= pas[i]) {
            hash = hash + (pas[i] - 48);
        }
        if ('a' <= pas[i] && 'z' >= pas[i]) {
            hash = hash + (pas[i] - 87);
        }
        if ('A' <= pas[i] && 'Z' >= pas[i]) {
            hash = hash + (pas[i] - 29);
        }
    }
    int n, p, q;
    cin >> n >> p >> q;
    int hashfun1 = hash % p;
    int hashfun2 = hash % q;
    int counter = 0;

    while (n--) {
        cin >> pas;
        int small = 0, big = 0;
        for (int i = 0; i < pas.length(); i++)
        {
            if (pas[i] >= 'A' && pas[i] <= 'Z')big++;
            if (pas[i] >= 'a' && pas[i] <= 'z')small++;
        }
        for (int i = 0; i < pas.length(); i++)
        {
            if (pas[i] + big >= 'A' && pas[i] + big <= 'Z') pas[i] = pas[i] + big;
            else if (pas[i] >= 'A' && pas[i] <= 'Z') {
                int tempVar = big;
                while (tempVar > 0) {
                    if (pas[i] == 'Z') {
                        pas[i] = 'A';
                        tempVar = tempVar - 1;
                    }
                    tempVar = tempVar - 1;
                    pas[i] = pas[i] + 1;
                }
            }
        }
        for (int i = 0; i < pas.length(); i++)
        {
            if (pas[i] + small >= 'a' && pas[i] + small <= 'z') pas[i] = pas[i] + small;
            else if (pas[i] >= 'a' && pas[i] <= 'z') {
                int tempVar = small;
                while (tempVar > 0) {
                    if (pas[i] == 'z') {
                        pas[i] = 'a';
                        tempVar = tempVar - 1;
                    }
                    pas[i] = pas[i] + 1;
                    tempVar = tempVar - 1;
                }
            }
        }
        int hash = 0;
        for (int i = 0; i < pas.length(); i++) {
            if ('0' <= pas[i] && '9' >= pas[i]) {
                hash = hash + (pas[i] - 48);
            }
            if ('a' <= pas[i] && 'z' >= pas[i]) {
                hash = hash + (pas[i] - 87);
            }
            if ('A' <= pas[i] && 'Z' >= pas[i]) {
                hash = hash + (pas[i] - 29);
            }
        }
        int hashfun3 = hash % p;
        int hashfun4 = hash % q;
        if (hashfun1 == hashfun3 && hashfun2 == hashfun4) {
            counter++;
        }
    }
    std::cout << counter;
    return 0;
}

Tests:测试:
Test 1. OK测试 1. 好的
Test 2. Wrong answer测试 2. 错误答案
Test 3. OK测试 3. 好的
Test 4. OK测试 4. 好的
Test 5. Wrong answer测试 5. 错误答案

3 of 5 tests passed. 5 次测试中的 3 次通过。

You have a few logic problems in your code.您的代码中有一些逻辑问题。 When you are rotating your upper and lower-case characters to their "encrypted" forms, you iterate through the password twice, and sometimes incorrectly rotate the characters.当您将大写和小写字符旋转为其“加密的”forms 时,您会重复密码两次,有时会错误地旋转字符。 Take for example just the line以这条线为例

if (pas[i] + big >= 'A' && pas[i] + big <= 'Z') pas[i] = pas[i] + big;

Consider the case where pas[i] == '9' and big == 8 .考虑pas[i] == '9'big == 8的情况。 You will end up transforming all of your 9 's into A s.您最终会将所有9转换为A

Now consider the line in the next loop现在考虑下一个循环中的行

if (pas[i] + small >= 'a' && pas[i] + small <= 'z') pas[i] = pas[i] + small;

Which will similarly transform some upper-case letters into lower-case if small is large enough.如果足够small ,它同样会将一些大写字母转换为小写字母。

You can also combine these two problems.您也可以将这两个问题结合起来。 Consider the case where pas[i] is originally Y , big is 1, little is 7. You'll transform Y --> Z , and then in the next step transform Z --> a .考虑一下pas[i]最初是Y的情况, big是 1, little是 7。您将转换Y --> Z ,然后在下一步中转换Z --> a

  1. Compartmentalize and abstract your single large main function into smaller functional blocks.将您的单个大型主 function 划分和抽象为更小的功能块。 This will allow you to reason about each piece individually instead of trying to keep the entirely of main() in your head.这将允许您单独推理每个部分,而不是试图将main()的全部内容保留在您的脑海中。 Humans have limited short-term memory.人类有有限的短期 memory。

Some suggested functions would include一些建议的功能包括

  • bool is_upper(char c)
  • bool is_lower(char c)
  • bool is_numeric(char c)
  • char rotate_upper(char c, int steps)
  • char rotate_lower(char c, int steps)
  1. Instead of looping through the password twice on your transformation step, consider looping through the password once.与其在转换步骤中循环两次密码,不如考虑循环一次密码。 If the character is upper-case, transform accordingly.如果字符是大写的,则进行相应的转换。 If it's lower-case, transform accordingly.如果是小写,则进行相应的转换。 This will prevent you from double-rotating some numbers.这将防止您重复旋转某些数字。

Combining all of the above, the two encryption loops of your main function could turn from:结合以上所有内容,您的主要 function 的两个加密循环可以从:

for (int i = 0; i < pas.length(); i++)
    {
        if (pas[i] + big >= 'A' && pas[i] + big <= 'Z') pas[i] = pas[i] + big;
        else if (pas[i] >= 'A' && pas[i] <= 'Z') {
            int tempVar = big;
            while (tempVar > 0) {
                if (pas[i] == 'Z') {
                    pas[i] = 'A';
                    tempVar = tempVar - 1;
                }
                tempVar = tempVar - 1;
                pas[i] = pas[i] + 1;
            }
        }
    }
    for (int i = 0; i < pas.length(); i++)
    {
        if (pas[i] + small >= 'a' && pas[i] + small <= 'z') pas[i] = pas[i] + small;
        else if (pas[i] >= 'a' && pas[i] <= 'z') {
            int tempVar = small;
            while (tempVar > 0) {
                if (pas[i] == 'z') {
                    pas[i] = 'a';
                    tempVar = tempVar - 1;
                }
                pas[i] = pas[i] + 1;
                tempVar = tempVar - 1;
            }
        }
    }

to

for (int i = 0; i < pas.length(); i++) {
    char c = pas[i];
    if (is_upper(c)) {
        pas[i] = rotate_upper(c, big);
    }
    else if (is_lower(c)) {
        pas[i] = rotate_lower(c, small);
    }
}

You can transform 30 lines of code into just under 10. That's much easier to read for both you, the developer, and for any potential reviewers.您可以将 30 行代码转换为不到 10 行代码。这对于您、开发人员和任何潜在的审阅者来说都更容易阅读。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM