zoukankan      html  css  js  c++  java
  • 经典算法C++版(参考一线码农博文)

    鉴于一线码农的算法博文基本通过C#完成,此处用C++再实现一遍,具体解法可参考其博文。

    地址:http://www.cnblogs.com/huangxincheng/category/401959.html。

    1.百钱买百鸡(降低时间复杂度)

    void NumofHen_1()
    {
        int x, y, z;
        for ( x = 1; x < 20; x++)
        {
            for ( y = 0; y < 33; y++)
            {
                z = 100 - x - y;
    
                if ((z % 3 == 0) && ((5 * x + 3 * y + z / 3) == 100))
                {
                    cout << "公鸡:" << x << " 母鸡:" << y << " 小鸡:" << z << endl;
                }
            }
        }
    }
    
    void NumofHen_2()
    {
        int x, y, z;
        for (size_t k = 0; k < 4; k++)
        {
            x = 4 * k;
            y = 25 - 7 * k;
            z = 75 + 3 * k;
            cout << "公鸡:" << x << " 母鸡:" << y << " 小鸡:" << z << endl;
        }
    }

    2.五家五井(不定方程组,运用数据为整数特性)

    代码省略,详情见一线码农相应博客。

    3.猴子吃桃(尾递归)

    题目:猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾就多吃了一个。第二天早上又将剩下的桃子吃了一半,还是不过瘾又多吃了一个。

             以后每天都吃前一天剩下的一半再加一个。到第10天刚好剩一个。问猴子第一天摘了多少个桃子?

    int SumPeach1(int day)
    {
        if (day == 10)
            return 1;
        else return 2 * SumPeach1(day + 1) + 2;
    }
    
    void NumofPeach_1()
    {
        int sum = SumPeach1(1);
        cout << "桃子数目:" << sum << endl;
    }
    
    //尾递归(剑指offer上有类似题目,判定二叉树是否平衡)
    int SumPeach_2(int day, int sum)
    {
        if (day == 10)
            return sum;
        else return SumPeach_2(day + 1, 2 * sum + 2);
    }
    
    void NumofPeach_2()
    {
        int sum = SumPeach_2(1, 1);
        cout << "桃子数目:" << sum << endl;
    }

    尾递归将每次计算结果进行传递,但是具体效果得看编译器是否进行了相应优化。

    此题还有更为简单的做法,具体为参考每次计算数值的规律性,与2的次方存在对应关系。

    4.寻找最长公共子序列(顺序,可以非连续)

    void sub_str(unsigned char** mat, const int i, const int j, const string& s,string& substr)
    {
        if (i == 0 || j == 0)
            return;
    
        if (3 == mat[i][j])
        {
            substr += s[j - 1];
            sub_str(mat, i - 1, j - 1, s, substr);
        }
        else
        {
            if (1 == mat[i][j])
                sub_str(mat, i - 1, j, s, substr);
            else if (2 == mat[i][j])
                sub_str(mat, i, j - 1, s, substr);
        }
    }
    
    //注意此处是寻找顺序的最长公共子序列(可以非连续)
    void LengthofSubstr_1(const string& s1, const string& s2)
    {
        int i, j, len1 = s1.length(), len2 = s2.length();
        if (0 == len1 || 0 == len2) return;
    
        int **matrix; //创建矩阵并初始化
        matrix = new int*[len1 + 1];
        //0无意义,1表示左边,2表示上面,3表示左上角
        unsigned char **signmat; 
        signmat = new unsigned char*[len1 + 1];
        for (i = 0; i < len1 + 1; i++)
        {
            matrix[i] = new int[len2 + 1];
            signmat[i] = new unsigned char[len2 + 1];
        }
        
        //此处其实无需全部初始化,初始化边界元素即可
        for (i = 0; i < len1 + 1; i++)
            for (j = 0; j < len2 + 1; j++)
            {
                matrix[i][j] = signmat[i][j] = 0;
            }
                
        //填充矩阵
        for (i = 1; i < len1 + 1; i++)
        {
            for (j = 1; j < len2 + 1; j++)
            {
                if (s1[i - 1] == s2[j - 1])
                {
                    signmat[i][j] = 3;
                    matrix[i][j] = matrix[i - 1][j - 1] + 1;
                }
                else
                {
                    //比较“左边”和“上边”的信息,选取最大值进行填充
                    if (matrix[i - 1][j] >= matrix[i][j - 1])
                    {
                        signmat[i][j] = 1;
                        matrix[i][j] = matrix[i - 1][j];
                    }
                    else
                    {
                        signmat[i][j] = 2;
                        matrix[i][j] = matrix[i][j - 1];
                    }
                }
            }
        }
    
        string substr; //将最长公共子序列输出
        sub_str(signmat, len1, len2, s2, substr);
        std::reverse(substr.begin(), substr.end());
    
        cout << "最大公共子序列长度为:" << matrix[len1][len2] << ";最长字串为:" << substr << endl;
    
        //释放矩阵
        for (i = 0; i < len1 + 1; i++)
        {
            delete[] matrix[i];
            delete[] signmat[i];
        }
        delete[] signmat;
        delete[] matrix;
    }

    个人建议还是将中间过程进行输出,这样方便理解,最好是看下面网址的图解。

    http://www.cnblogs.com/huangxincheng/archive/2012/11/11/2764625.html

    不过博客里面的图解初始位置应该为0,自己输出中间变量的就会比较清楚。漂亮的解法。

    5.字符串相似度

    对于两个字符串A和B,通过基本的增删改将字符串A改成B,或者将B改成A,在改变的过程中我们使用的最少步骤称之为“编辑距离”。

    虽然没太看懂,不过这个解题思路和上面类似,仅仅是初始化方式进行了改变,意义完全不一样了,赞

    int MinofThree(const int x1, const int x2, const int x3)
    {
        int min = x1 < x2 ? x1 : x2;
        return x3 < min ? x3 : min;
    }
    
    int SameofStr(const string& s1, const string& s2)
    {
        int i,j,len1 = s1.length(), len2 = s2.length();
        if (len1 <= 0 || len2 <= 0) return 0;
    
        int **matrix = NULL;
        matrix = new int*[len1 + 1];
        for (i = 0; i < len1 + 1; i++)
            matrix[i] = new int[len2 + 1];
        //初始化矩阵,跟前面的求公共字符串初始化不同  
        for (i = 0; i < len1 + 1; i++)
            matrix[i][0] = i;
        for (i = 0; i < len2 + 1; i++)
            matrix[0][i] = i;
    
        for ( i = 1; i < len1+1; i++)
        {
            for (j = 1; j < len2 + 1; j++)
            {
                if (s1[i - 1] == s2[j - 1])
                {
                    matrix[i][j] = matrix[i - 1][j - 1];
                }
                else
                {
                    matrix[i][j] = MinofThree(matrix[i - 1][j], matrix[i][j - 1], matrix[i - 1][j - 1]) + 1;
                }
            }
        }
        
        int res = matrix[len1][len2];
        for (i = 0; i < len1 + 1; i++)
            delete[] matrix[i];
        delete[] matrix;
    
        //返回字符串的编辑距离
        return res;
    }

    6.KMP算法(暂时未理解)

    void GetNextVal(int next[], const string& str)
    {
        //前缀起始位置以及后缀起始位置
        int k = -1, j = 0;
        next[j] = -1;
    
        while (j < str.length() - 1)
        {
            if (-1 == k || str[k] == str[j])
            {
                next[++j] = ++k;
            }
            else
            {
                k = next[k];
            }
        }
    }
    
    //s1为主串,s2为子串
    int KMP(const string& s1, const string& s2)
    {
        int i = 0, j = 0, len1 = s1.length(), len2 = s2.length();
    
        if (len1 < len2 || len1 <= 0 || len2 <= 0)
            return -1;
        else if (len1 == len2)
        {
            for (i = 0; i < len1; i++)
                if (s1[i] == s2[i])
                    return -1;
            return 0;
        }
    
        int *next = new int[len2];
        memset(next, 0, sizeof(next));
        GetNextVal(next, s2);
    
        while (i < len1&&j < len2)
        {
            if (-1 == j || s1[i] == s2[j])
            {
                ++i;++j;
            }
            else 
            {
                j = next[j];
            }
        }
    
        delete[] next;
        if (j == len2)
            return i - len2;
        else return -1;
    }

    7.改进版KMP算法

    void getnext(const string& T,int next[])
    {
        next[0] = -1;
        int i = 0, j = -1; //分别表示前后缀串的初始位置
        
        while (i < T.length() - 1)
        {
            if (-1 == j || T[i] == T[j])
            {
                ++i;++j;
                if (T[i] != T[j])
                    next[i] = j;
                else next[i] = next[j];
            }
            else
            {
                j = next[j];
            }
        }
    }
    
    //pos表示从主串的第pos个位置进行匹配
    int KMP(const string& S, const string& T, int pos = 0)
    {
        int i = pos, j = -1, len1 = (int)S.length(), len2 = (int)T.length();
        int *next = new int[T.length()];
    
        getnext(T, next);
        //此处不能使用i < S.length() && j < T.length()
        //因为length()函数返回的为size_t,负数与其比较时会转换为size_t
        while (i < len1&&j < len2) 
        {
            if ((-1 == j) || S[i] == T[j])
            {
                ++i;++j;
            }
            else
            {
                j = next[j];
            }
        }
        delete[] next;
    
        if (j == T.length())
            return i - T.length();
        else return -1;
    }

    8.华为机试题目,猴子分桃

    //猴子分桃算法
    long long NumOfPeach(int n)
    {
        if (n < 3 || n>9)
            return -1;
    
        long long i, j, num, tmp;
        for (i = 25; ; ++i)
        {
            num = i;
            for (j = 0; j < n; j++)
            {
                if (num%n == 1)
                {
                    tmp = (num - 1) / n;
                    num = num - 1 - tmp;
                }
                else break;
            }
            if (j == n)
                break;
        }
        return i;
    }
  • 相关阅读:
    day103 跨域请求 与频率访问限制.
    day 102 GIT 的使用方法.
    day 101 天
    day 100天 VUE 父子传值,单页面.
    JS 在元素后插入元素
    JS 网页加载后执行多个函数
    MySQL 一般操作语句
    PHP 通过设置表单元素name属性生成数组
    PHP SQL语气中value必须添加单引号
    PHP 单引号和双引号的区别
  • 原文地址:https://www.cnblogs.com/jason1990/p/4756894.html
Copyright © 2011-2022 走看看