ARTS 第十周打卡

Algorithm : 做一个 leetcode 的算法题

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""。

示例 1:

输入: ["flower","flow","flight"]
输出: "fl"
示例 2:

输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
说明:

所有输入只包含小写字母 a-z 。

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        int iSize = strs.size();
        if(iSize <= 0)
        {
            return "";
        }
        
        if(1 == iSize)
        {
            return strs[0];
        }
        
        int iMaxPrefix = 0;
        while(true)
        {
            for(int i = 0; i < iSize; i++)
            {
                if(iMaxPrefix >= (int)strs[i].size())
                {
                    return strs[i].substr(0, iMaxPrefix);
                }
                
                char ch = strs[0][iMaxPrefix];
                if(ch != strs[i][iMaxPrefix])
                {
                    return strs[i].substr(0, iMaxPrefix);
                }
            }
            iMaxPrefix++;
        }
        
        
    }
};


Review : 阅读并点评一篇英文技术文章

11.1.1 Numeric Type Overview
A summary of the numeric data types follows. For additional information about properties and storage requirements of the numeric types, see Section 11.2, “Numeric 
Types”, and Section 11.8, “Data Type Storage Requirements”.

For integer types, M indicates the maximum display width. The maximum display 
width is 255. Display width is unrelated to the range of values a type 
can contain, as described in Section 11.2, “Numeric Types”.
对于整数类型,M表示最大显示宽度,最大显示宽度为255,显示的宽度与包含类型的值范围无关。

For floating-point and fixed-point types, M is the total number of digits that can be stored.

As of MySQL 8.0.17, the display width attribute is deprecated for integer data types and will be removed in a future MySQL version.
从mysql8.0.17开始,对于整数数据类型,显示宽度属性被弃用;

If you specify ZEROFILL for a numeric column, MySQL automatically adds the UNSIGNED attribute to the column.
如果数值列被指定ZEROFILL,Mysql会自动增加unsigned属性的值到该列;

As of MySQL 8.0.17, the ZEROFILL attribute is deprecated for numeric data types 
and will be removed in a future MySQL version. Consider using an alternative means of producing the effect of this attribute. For example, applications could use the LPAD() function to zero-pad numbers up to the desired width, or they could store 
the formatted numbers in CHAR columns.
从mysql8.0.17开始,对于数字类型,zerofill属性将被弃用,并且将被删除在以后的版本中,考虑使用另外一种方法来替换这中属性,例如,应用程序可以使用LPAD()函数将零位数设置为所需要的宽度,或者将格式化的数字存储在char列中;


Numeric data types that permit the UNSIGNED attribute also permit SIGNED. 
However, these data types are signed by default, so the SIGNED attribute has no 
effect.

As of MySQL 8.0.17, the UNSIGNED attribute is deprecated for columns of type FLOAT, DOUBLE, and DECIMAL (and any synonyms) and will be removed in a future MySQL version. Consider using a simple CHECK constraint instead for such columns.
从mysql8.0.17开始,对于float/double/decimal(以及任何同义词)不推荐使用unsigned属性,并在奖励啊的版本中被删除,考虑使用简单的额CHECK来约束这些列。

SERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE.

SERIAL DEFAULT VALUE in the definition of an integer column is an alias for NOT NULL AUTO_INCREMENT UNIQUE.



Tips : 学习一个技术技巧

#ifndef __TIMER_AXIS_H__
#define __TIMER_AXIS_H__

#include "Common.h"

#ifdef SUPPORT_TIMER

#include <string>
#include <list>
#include <vector>
#include <map>
#include "TimerHandler.h"
#include "Singleton.h"
#include "StringHash.h"
using namespace stdext;

// 定义数据类型
#ifdef WIN32
#include <windows.h>
#else
typedef unsigned long DWORD;
#endif

#ifdef RKT_COMPILER_MSVC
#pragma warning(push)
#pragma warning(disable : 4251)
#endif

namespace rkt
{

/*
    *  问题:
    *  1.OnCheck调用频率大于单位时间刻度时怎么处理?
    *  2.多线程支持
    *  3.长Timer怎么处理?
    *  4.需要支持调试功能
    *
    *  分析:
    *  1.时间轴的核心实际是一个高效的排序算法
    *  2.此算法对插入删除操作要求极高
    *  3.主要是插入排序,不是对一堆数字整体排序
    *  4.插入排序实际最主要的要求是如何尽快找到一个值大致所在的位置
    *  
    *  设计方案:
    *  1.把时间轴分成N个刻度,每个刻度内保存此段时间内需要调用的Timer
    *  2.长Timer折算成N个短Timer回调
    *  3.因为在单位时间刻度内只能也只需调用几次,所以同一刻度内的Timer不需排序
    *  4.完整时间轴由N个不同长度段的子时间轴组合而成,这样定时频率在1秒以下
    *    需要频繁调用的定时器可以放在一个每格长度1ms长度等于1秒极度细化的时间轴中
    *    以达到最高效率
    *  5.避免填加删除Timer时的查找操作可以大大提高效率.
    */

//////////////////////////////////////////////////////////////////////////
/************************* TimerAxis Config *****************************/

// 推荐检查频率    :    16(ms)
// 推荐时间刻度 :       64(ms)
#define CHECK_FREQUENCY 16 //精确到16ms
#define TIME_GRID 64

// 时间轴长度
#define TIME_AXIS_LENGTH 720000     // 这个为什么分配这个值???
#define INVALID_TIMER 0xffffffff
#define INFINITY_CALL 0xffffffff

// 是否允许进行定时器统计
//#    define SUPPORT_TIMEAXIS_STAT

#define SUPPORT_TIMEAXIS_DEBUG_INFO // 是否支持调试信息

struct SAnalyseTimer
{
public:
    float m_fAvgTime;
    float m_fMaxTime;
    float m_fCount;
};
typedef hash_map<std::string, SAnalyseTimer> TMAP_ANALYSETYPE;

struct SStatTimer
{
    int m_iCount;
    std::string m_szDebugInfo;

    SStatTimer(void)
    {
        m_iCount = 0;
        m_szDebugInfo.clear();
    }
};
typedef StrHashMap<SStatTimer> TMAP_STATTYPE;

//////////////////////////////////////////////////////////////////////////

class RKT_EXPORT TimerAxis : public SingletonEx<TimerAxis>
{
public:
    /**
        @purpose                : 设置一个定时器
        @param     dwTimerID      : 定时器ID
        @param   dwInterval     : 定时器调用间隔
        @param   pHandler       : 处理接口
        @param   dwCallTimes    : 调用次数,默认调用无穷次
        @param   pszDebugInfo   : 调试信息
        @return                    : 如果设置成功则返回true
        */
    bool TimerAxis::SetTimer(DWORD dwTimerID, DWORD dwInterval, ITimerHandler *pHandler, DWORD dwCallTimes = INFINITY_CALL, const char *pszDebugInfo = NULL);

    /**
        @purpose          : 删除定时器
        @param     timerID  : 定时器ID
        @param   handler  : 处理接口
        @return              : 返回是否删除成功
        */
    bool KillTimer(DWORD timerID, ITimerHandler *handler);

    /**  删除定时器对象内部的所有时钟 added by PeakGao 2011.5.3
        @param handler 定时器处理者    */
    void KillTimer(ITimerHandler *handler);

    void CheckTimer(ulong timeout = 0);

    TMAP_STATTYPE *GetStateInfo(void);

    DWORD GetTimerCount() { return m_dwTimerCount; }

    void OutputAnalyseInfo();

    TimerAxis();

    virtual ~TimerAxis();

protected:
    /// 取得当前时间,你可以修改成使用其他API
    inline DWORD GetTickCount() { return ::GetTickCount(); }

protected:
    struct Timer
    {
        DWORD m_dwTimerID;
        DWORD m_dwInterval;     // 定时器调用间隔
        DWORD m_dwCallTimes;    // 总共需要回调多少次
        DWORD m_dwLastCallTick; // 最后一次调用的时间
        DWORD m_dwGridIndex;    // 所在的时间刻度
        ITimerHandler *m_pHandler;

#ifdef SUPPORT_TIMEAXIS_DEBUG_INFO
        std::string m_pszDebugInfo;
#endif
        std::list<Timer *>::iterator m_itPos; // 在时间刻度中的iterator,加快搜索
    };

    typedef std::list<Timer> TIMER_INFO;        // 存在ITimerHandler中的定时器临时信息
    typedef std::list<Timer *> TIMER_LIST;      // 每一个时间刻度中存放的定时器列表
    typedef std::vector<TIMER_LIST> TIMER_AXIS; // 保存所有时间刻度信息的时间轴结构

    TIMER_AXIS m_astTimerAxis;
    DWORD m_dwLastCheckTick;  // 最后一次检查的时间
    DWORD m_dwInitializeTime; // 时间轴初始时间
    DWORD m_dwTimerCount;     // 定时器个数

#ifdef SUPPORT_TIMEAXIS_STAT
    TMAP_STATTYPE m_mapStatType; // 按定时器来统计数量
#endif
    TMAP_ANALYSETYPE m_mapAnalyseType; //定时器调用 耗时分析统计表
};

} // namespace rkt

#ifdef RKT_COMPILER_MSVC
#pragma warning(pop)
#endif

#endif // #ifdef SUPPORT_TIMER

#endif // __TIMER_AXIS_H__


#include "../Include/TimerAxis.h"

using namespace rkt;


TimerAxis::TimerAxis()
{
    m_astTimerAxis.resize((TIME_AXIS_LENGTH + TIME_GRID - 1) / TIME_GRID);
    m_dwInitializeTime = GetTickCount();
    m_dwLastCheckTick = m_dwInitializeTime;
}

TimerAxis::~TimerAxis()
{
    for (int i = 0; i < (int)m_astTimerAxis.size(); i++)
    {
        for (TIMER_LIST::iterator it = m_astTimerAxis[i].begin(); it != m_astTimerAxis[i].end(); ++it)
        {
            Timer *pTimer = *it;
            if (pTimer)
            {
                KillTimer(pTimer->m_dwTimerID, pTimer->m_pHandler);
            }
        }
    }
}

/**
@purpose          : 设置一个定时器
@param     timerID  : 定时器ID
@param   interval : 定时器调用间隔
@param   handler  : 处理接口
@param   callTimes: 调用次数,默认调用无穷次
@param   debugInfo: 调试信息
@return              : 如果设置成功则返回true
*/
bool TimerAxis::SetTimer(DWORD dwTimerID, DWORD dwInterval, ITimerHandler *pHandler, DWORD dwCallTimes, const char *pszDebugInfo)
{
    // 1.条件检查
    if (NULL == pHandler || 0 == dwInterval)
    {
        return false;
    }

    void **ppTimeInfo = pHandler->GetTimerInfoPtr();
    assert(ppTimeInfo);

    TIMER_INFO *pTimerInfo = *(TIMER_INFO **)ppTimeInfo;
    if (NULL == ppTimeInfo)
    {
        pTimerInfo = new TIMER_INFO;
        *ppTimeInfo = pTimerInfo;
    }

    // 2.检查是否已经添加这个timer
    for (TIMER_INFO::iterator it = pTimerInfo->begin(); it != pTimerInfo->end(); it++)
    {
        if (it->m_dwTimerID == dwTimerID)
        {
            return false;
        }
    }

    // 3.添加一个新的定时器
    Timer stTimer;
    stTimer.m_dwTimerID = dwTimerID;
    stTimer.m_dwInterval = dwInterval;
    stTimer.m_dwCallTimes = dwCallTimes;
    stTimer.m_dwLastCallTick = m_dwLastCheckTick;
    stTimer.m_pHandler = pHandler;

    if (pszDebugInfo)
    {
        stTimer.m_pszDebugInfo = pszDebugInfo;
    }

    // 计算所在的刻度
    stTimer.m_dwGridIndex = ((stTimer.m_dwLastCallTick + stTimer.m_dwInterval - m_dwInitializeTime) / TIME_GRID) % m_astTimerAxis.size();

    pTimerInfo->push_back(stTimer);

    // 4.添加到时间刻度
    Timer& rstTimerRef = pTimerInfo->back();    // 这里不能使用 stTimer 临时变量
    m_astTimerAxis[stTimer.m_dwGridIndex].push_back(&rstTimerRef);
    rstTimerRef.m_itPos = --m_astTimerAxis[stTimer.m_dwGridIndex].end();

    return true;
}

/**
@purpose          : 删除定时器
@param     timerID  : 定时器ID
@param   handler  : 处理接口
@return              : 返回是否删除成功
*/
bool TimerAxis::KillTimer(DWORD dwTimerID, ITimerHandler *pHandler)
{
    void **ppTimerInfo = pHandler->GetTimerInfoPtr();
    assert(ppTimerInfo);

    TIMER_INFO *pTimerInfo = *(TIMER_INFO **)ppTimerInfo;

    // 根本就没添加
    if (NULL == pTimerInfo)
    {
        return;
    }

    // 检查是否已经添加了这个Timer
    for (TIMER_INFO::iterator it = pTimerInfo->begin(); it != pTimerInfo->end(); it++)
    {
        if (it->m_dwTimerID == dwTimerID)
        {
            pTimerInfo->erase(it);
            if (pTimerInfo->empty())
            {
                delete pTimerInfo;
                pTimerInfo = NULL;
            }

            return true;
        }
    }

    return false;
}

/**  删除定时器对象内部的所有时钟
@param handler 定时器处理者    */
void TimerAxis::KillTimer(ITimerHandler *pHandler)
{
    void **ppTimerInfo = pHandler->GetTimerInfoPtr();
    assert(ppTimerInfo);

    TIMER_INFO *pTimerInfo = *(TIMER_INFO **)ppTimerInfo;

    // 根本就没添加
    if (NULL == pTimerInfo)
    {
        return;
    }

    pTimerInfo->clear();

    delete pTimerInfo;
    pTimerInfo = NULL;

}

void TimerAxis::CheckTimer(ulong timeout)
{
    DWORD dwNowTicks = GetTickCount();
    if (dwNowTicks - m_dwLastCheckTick < CHECK_FREQUENCY)
    {
        return;
    }

    DWORD dwStartGrid = ((m_dwLastCheckTick - m_dwInitializeTime) / TIME_GRID) % m_astTimerAxis.size();
    DWORD dwCurGrid = ((dwNowTicks - m_dwInitializeTime) / TIME_GRID) % m_astTimerAxis.size();
    m_dwLastCheckTick = dwNowTicks;

    // 遍历所有时钟
    do 
    {
        TIMER_LIST rstTimeList = m_astTimerAxis[m_dwLastCheckTick];
        for (TIMER_LIST::iterator it = rstTimeList.begin(); it != rstTimeList.end();)
        {
            Timer* pTimer = *it;
            if (NULL == pTimer)
            {
                it = rstTimeList.erase(it); // 删除会指向下一个元素
                continue;
            }

            if (dwNowTicks - pTimer->m_dwLastCallTick >= pTimer->m_dwInterval)
            {
                // 触发定时器
                pTimer->m_pHandler->OnTimer(pTimer->m_dwTimerID);

                pTimer->m_dwLastCallTick = dwNowTicks;
                pTimer->m_dwCallTimes -= 1;

                if (0 == pTimer->m_dwCallTimes)
                {
                    KillTimer(pTimer->m_dwTimerID, pTimer->m_pHandler);
                }
                else
                {
                    pTimer->m_dwGridIndex = ((pTimer->m_dwLastCallTick + pTimer->m_dwInterval - m_dwInitializeTime) / TIME_GRID) % m_astTimerAxis.size();
                    it = rstTimeList.erase(it);
                    m_astTimerAxis[pTimer->m_dwGridIndex].push_back(pTimer);
                    pTimer->m_itPos = --m_astTimerAxis[pTimer->m_dwGridIndex].end();
                    continue;
                }
            }

            it++;
        }

        // 递进大下一个刻度
        if (dwStartGrid == dwCurGrid)
        {
            break;
        }

        dwStartGrid = (dwStartGrid + 1) % m_astTimerAxis.size();

    } while (dwStartGrid != dwCurGrid);
}

TMAP_STATTYPE *TimerAxis::GetStateInfo(void)
{
}

void TimerAxis::OutputAnalyseInfo()
{
}


Share : 分享一篇有观点和思考的技术文章

C++ new delete 常踩的坑

原文链接:https://wetest.qq.com/lab/view/318.html?from=adsout_qqtips_past2_318&sessionUserType=BFT.PARAMS.230036.TASKID&ADUIN=664510732&ADSESSION=1501034659&ADTAG=CLIENT.QQ.5533_.0&ADPUBNO=26719

posted @ 2019-09-08 21:54  VIP丶可乐  阅读(194)  评论(0编辑  收藏  举报