基於c++11泛型編程開發一個LeetCode本地開發測試組件

LeetCode初次接觸感覺還不錯,重點是可以對比討論共同實現的一段代碼,https://leetcode.com。

處理複雜問題不適合在OJ上直接開發,本地調試更簡單。暫時(我想應該會有)未發現可以直接拿來運行的框架,自己簡單實現一個,未來發現更好的再補充。

注意:只以用c++11,g++編譯選項-std=c++11

一個需要兩個文件,下載文件

leetcode.h 包含一些流程控制和通用api(臨時寫的,需要時補全)

main.cpp 實現一些差異化接口即可

功能:執行指定的數據的測試,自動進行5組隨機測試

驗證:可以人工覈驗,也可以指定一個確定的通過代碼,對比校驗另一下

用法 : class Q1 : public Solution<RetType, ParamList>

RetType表示接口返回類型,具體題目具體替換,不要用引用,不然模板有衝突

ParamList是逗號間隔的所有函數參數列表,這裏使用了不定參數模板

實現基類所有純虛函數

後文給出了第一題和第3題的示例Demo。


一、leetcode.h

#include <iostream>
#include <random>
#include <map>
#include <unordered_map>
#include <cassert>
#include <algorithm>
#include <cstring>
using namespace std;

class Interface
{
public:
        virtual void RandomTest(uniform_int_distribution<int>& u, default_random_engine& e) = 0;
};

template<typename RT, typename ...ARGS>
class Solution : virtual public Interface
{
        typedef RT (Solution::*deal_fun_t)(ARGS...);
        //定義5個回調算法
        virtual RT FUN_NAME_0(ARGS...) { return RT(); }
        virtual RT FUN_NAME_1(ARGS...) { return RT(); }
        virtual RT FUN_NAME_2(ARGS...) { return RT(); }
        virtual RT FUN_NAME_3(ARGS...) { return RT(); }
        virtual RT FUN_NAME_4(ARGS...) { return RT(); }
        virtual RT FUN_NAME_5(ARGS...) { return RT(); }
        deal_fun_t m_fun[5];
        //
        virtual bool CheckRst(RT&, RT&, ARGS...) const = 0;
        virtual void DumpInput(ARGS...) = 0;
        //
        bool m_debug;
        int m_id;
public:
        void SetConf(int id, bool debug) { m_id =id; m_debug = debug; }
        //構造初始化指定算法
        Solution(int no = 0)
        {
                m_fun[0] = &Solution::FUN_NAME_0;
                m_fun[1] = &Solution::FUN_NAME_1;
                m_fun[2] = &Solution::FUN_NAME_2;
                m_fun[3] = &Solution::FUN_NAME_3;
                m_fun[4] = &Solution::FUN_NAME_4;
                m_fun[5] = &Solution::FUN_NAME_5;
        }

        //測試並打印相關信息
        void Test(ARGS...arg)
        {
                cout << "----------------" << endl;
                DumpInput(arg...);
                auto rst1 = FUN_NAME_0(arg...);
                auto rst2 = (this->*m_fun[m_id])(arg...);
                if(CheckRst(rst1, rst2, arg...))
                        cout << "succ" << endl;
                else
                {
                        cout << "fail" << endl;
                        assert(!m_debug);
                }
        }
        //公共庫存
        //隨機vector
        vector<int> RandomVector(uniform_int_distribution<int>& u, default_random_engine& e, int min)
        {
                int len = u(e)+min;
                vector<int> data(len);
                for(int i = 0; i < len; i++)
                        data[i] = u(e);
                return data;
        }
        //隨機字符串
        string RandomString(uniform_int_distribution<int>& u, default_random_engine& e, int min)
        {
                int len = u(e)+1;
                static char s_str[] = "abcdefghijklmnopqrstuvwxvzABCDEFGHIJKLMNOPQRSTUVWXVZ";
                char* ptr = s_str, *end=s_str+52;
                string rst;
                for(int i = 0; i < len; i++)
                {
                        ptr += u(e);
                        if(ptr >= end)
                                ptr = s_str;
                        rst += (char)ptr[0];
                }
                return rst;
        }
        //vector<int>轉字符串
        string VecToStr(vector<int>& arr, char sep)
        {
                string str;
                char buf[32];
                for(auto &i : arr)
                {
                        sprintf(buf, "%d%c", i, sep);
                        str += buf;
                }
                return str;
        }
};

//main
Interface* GetObj(int argc, char* argv[], char* env[]);
int main(int argc, char* argv[], char* env[])
{
        Interface* s = GetObj(argc, argv, env);
        if(s == nullptr)
                return 0;
        //隨機測試
        uniform_int_distribution<int> u(0, 9);
        default_random_engine e;
        e.seed(time(0));
        for(int i = 0; i < 5; i++)                      //隨機測試5組
                s->RandomTest(u, e);
        return 0;
}

第一題示例:

#include "leetcode.h"

//use class Q1 : public Solution<RetType, ParamList>

class Q1 : public Solution<int, string>
{
public:
        Q1(int id, bool debug = true)
        {
                SetConf(id, debug);
        }
        //一次隨機測試
        void RandomTest(uniform_int_distribution<int>& u, default_random_engine& e) override
        {
                Test(RandomString(u, e, 0));
        }
        //輸出輸入信息
        void DumpInput(string str) override
        {
                cout << "input: " << str << endl;
        }
        //輸出字符串化以比較  r0是標準函數返回結果, r1是自定義函數結果
        bool CheckRst(int& r0, int& r1, string s) const override
        {
                cout << "rst " << r0 << "," << r1 << endl;
                return r0 == r1;
        }
        int FUN_NAME_0(string s) override
        {
                vector<int> pos(127, -1);
                int max = 0;
                int repeat = -1;
                int len = s.length();
                for(int i = 0; i < len; i++)
                {
                        if(pos[s[i]] > repeat)
                                repeat = pos[s[i]];
                        pos[s[i]] = i;
                        int len = i - repeat;
                        if(len > max)
                                max = len;
                }
                return max;
        }
        int FUN_NAME_1(string s) override
        {
                char c[128];
                memset(c, 0, sizeof(c));
                const char* p = s.c_str();
                int len1 = 0, max = 0;
                while(*p != '\0')
                {
                        int pos = (char)*p;
                        if(c[pos] != 0)
                        {
                                while(p[-len1] != *p)
                                {
                                        pos = p[-len1];
                                        --c[pos];
                                        --len1;
                                }
                                pos = p[-len1];
                                --c[pos];
                                --len1;
                        }
                        pos = *p;
                        c[pos]++;
                        p++;
                        len1++;
                        if(max < len1)
                                max = len1;
                }
                return max;
        }
};

Interface* GetObj(int argc, char* argv[], char* env[])
{
        Q1* s = new Q1(1, false);                                               //指定使用1號算法
        //返回之前可以進行一些內部測試
        s->Test("heecagga");
        s->Test("eecdb");
        s->Test("dfhgd");
        s->Test("abcabcbb");
        s->Test("bbbbb");
        s->Test("pwwkew");
        return s;
}


第三題示例

#include "leetcode.h"

//use class Q1 : public Solution<RetType, ParamList>
class Q3 : public Solution<vector<int>, vector<int>, int>
{
public:
        Q3(int id, bool debug = true)
        {
                SetConf(id, debug);
        }
        //一次隨機測試
        void RandomTest(uniform_int_distribution<int>& u, default_random_engine& e) override
        {
                Test(RandomVector(u, e, 2), u(e));
        }
        //輸出輸入信息
        void DumpInput(vector<int> nums, int target) override
        {
                cout << "sum: " << target << " | " << VecToStr(nums, ' ') << endl;
        }
        //輸出字符串化以比較  r0是標準函數返回結果, r1是自定義函數結果
        bool CheckRst(vector<int>& r0, vector<int>& r1, vector<int> nums, int target) const override
        {
                cout << r0[0] << "," << r0[1] << endl << r1[0] << "," << r1[1] << endl;
                return nums[r1[0]] + nums[r1[1]] == nums[r0[0]] + nums[r0[1]];  //1和2結果對比
                //return (nums[r1[0]] + nums[r1[1]] == target) && (nums[r0[0]] + nums[r0[1]] == target) //全量校驗以避免參考答案有誤
        }
        //算法1,普通算法,a+b=target,遍歷一次數組,每個數,即可能是a,也可能是b,將a起來。如果找到了當前數的a,則成功
        //9ms 54.37,  再提交2次,6ms和12ms
        vector<int> FUN_NAME_0(vector<int> nums, int target) override
        {
                unordered_map<int, int> subs;
                const int max = nums.size();
                for(int i = 0; i < max; i++)
                {
                        auto it = subs.find(target-nums[i]);
                        if(it != subs.end())
                                return vector<int> {it->second, i};
                        subs[nums[i]] = i;
                }
                return vector<int> {-1, -1};
        }
        //算法2,改進最佳答案,用map同時實現排序和反查,降低反查代價,損耗一些排序性能(相對快速排序)
        //18ms, 41.35%, 並沒有成功,原因是數據量小的情況下,得不償失
        vector<int> FUN_NAME_1(vector<int> nums, int target) override
        {
                multimap<int, int> org_pos;
                for(size_t i = 0; i < nums.size(); i++)
                        org_pos.insert(pair<int,int>(nums[i], i));
                auto it_beg = org_pos.begin();
                auto it_end = --org_pos.end();
                while(it_beg != it_end)
                {
                        int val = it_beg->first + it_end->first;
                        if(val == target)
                        {
                                if(it_beg->second < it_end->second)
                                        return vector<int> {it_beg->second, it_end->second};
                                else
                                        return vector<int> {it_end->second, it_beg->second};
                        }
                        if(val > target)
                                it_end--;
                        else if(val < target)
                                it_beg++;
                }
                return vector<int> {-1, -1};
        }
};

Interface* GetObj(int argc, char* argv[], char* env[])
{
        Q3* s = new Q3(1, false);                                               //指定使用1號算法
        //返回之前可以進行一些內部測試
        //s.Test(vector<int> {3,3}, 6);         //指定的固定測試數據
        //s.Test(vector<int> {2,7,11,15}, 9);
        return s;
}


一個非常臨時的Makefile

CXXFLAGS= -std=c++11 -g -Wall
main: binid1 binid3
        ./binid1
        ./binid3
binid1: id1.cpp
        g++ ${CXXFLAGS} id1.cpp -o binid1
binid3: id3.cpp
        g++ ${CXXFLAGS} id3.cpp -o binid3


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章