剑指offer.C++.code46-50

46. 圆圈中最后剩下的数【约瑟夫环问题】

  • 有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!_)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
// Solution:(1)使用环形链表模拟,时间复杂度O(mn),空间复杂度O(n);
//          (2)直接找出最后一个数字规律
class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if (n < 1 || m < 1) 
            return -1;
        list<int> numbers;
        for (int i = 0; i < n; i ++) 
            numbers.push_back(i);
        list<int>::iterator cur = numbers.begin();
        while (numbers.size() > 1) {
            for (int i = 1; i < m; i ++) {
                cur ++;
                if (cur == numbers.end())    // 模拟环尾
                    cur = numbers.begin();
            }
            list<int>::iterator deleteIt = cur;
            cur ++;
            if (cur == numbers.end()) 
                cur = numbers.begin();
            numbers.erase(deleteIt);
        }
        return *(cur);
    }
};
// Solution:(1)使用环形链表模拟,时间复杂度O(mn),空间复杂度O(n);
//          (2)直接找出最后一个数字规律,f(n,m) = 0, n=1,时间O(n),空间O(1)
//                                  f(n,m) = [f(n-1, m)+m]%n, n>1
class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if (n < 1 || m < 1) 
            return -1;
        int last = 0;
        for (int i = 2; i <= n; i ++)
            last = (last + m) % i;
        return last;
    }
};

47. 求1+2+...+n【发散思维】

  • 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
// Solution:(1)利用构造函数求解
class Temp {
public:
    Temp() { N ++; Sum += N;}
    static void Reset() { N = 0; Sum = 0;}
    static unsigned int GetSum() { return Sum;}
private:
    static unsigned int N;
    static unsigned int Sum;
};

unsigned int Temp::N = 0;
unsigned int Temp::Sum = 0;

class Solution {
public:
    int Sum_Solution(int n) {
        Temp::Reset();
        Temp *a = new Temp[n];
        delete []a;
        a = NULL;
        return Temp::GetSum();
    }
};
// Solution:(2)利用虚函数求解,一个函数递归,一个函数判断终止条件
class A;
A* Array[2];

class A {
    public:
    virtual unsigned int Sum(unsigned int n) {
        return 0;
    }
};

class B: public A {
    public:
    virtual unsigned int Sum(unsigned int n) {
        return Array[!!n]->Sum(n-1) + n;
    }
};

class Solution {
public:
    int Sum_Solution(int n) {
        A a;
        B b;
        Array[0] = &a;
        Array[1] = &b;
        int value = Array[1]->Sum(n);
        return value;
    }
};
// Solution:(3)利用函数指针求解
typedef int (*fun) (int);   
class Solution {
public:
    static int Sum_terminator(int n) {
        return 0;
    }
    static int Sum_Solution(int n) {
        static fun f[2] = {Sum_terminator, Sum_Solution};
        return n + f[!!n](n-1);
    }
};

48. 不用加减乘除做加法

  • 写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
// Solution:位运算
class Solution {
public:
    int Add(int num1, int num2)
    {
        int sum, carry;
        do {
            sum = num1 ^ num2;
            carry = (num1 & num2) << 1;
            
            num1 = sum;
            num2 = carry;
        } while (num2 != 0);
        return num1;
    }
};

49. 把字符串转换成整数

  • 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0

输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
示例1
输入
+2147483647
1a33
输出
2147483647
0

// 考虑:(1)输入""; (2)输入非0-9; (3)输入"+/-"等; (4)溢出
class Solution {
public:
    int StrToInt(string str) {
        int gFlag = -1;
        int len = str.size();
        if (len  == 0) {
            gFlag = 1;
            return 0;
        }
        int minus = 1;
        long long num = 0;
        
        int i = 0;
        if (str[i] == '+') {
            i ++;
        } else if (str[i] == '-') {
            i ++;
            minus = -1;
        }
        
        while (str[i] != '\0') {
            if (str[i] >= '0' && str[i] <= '9') {
                num = num*10 + str[i]-'0';
                i ++;
                if (((minus > 0) && (num > 0x7FFFFFFF)) || 
                    ((minus < 0) && (num > 0x80000000))) {
                    num = 0;
                    gFlag = 2;
                    break;
                }
            } else {
                num = 0;
                gFlag = 3;
                break;
            }
        }
        return (int)minus*num;
    }
};

50. 树中两个结点的最低公共祖先

  • 输入两个结点,求他们的最低公共祖先
  • 二叉树:判断两个结点与当前结点的大小关系,第一个在两节点之间的值即最低公共祖先。
solution
  • 非二叉树,有指向父节点的指针:(转换为求两个链表第一个公共结点)
solution
  • 非二叉树,没有指向父节点的指针: 判断子树中同时包含两个结点,并判断该节点的子节点子树不同时包含两个结点,该结点就是最低公共祖先。使用数组保存两个结点所在的路径,以减少重复计算子树情况。
solution1

solution2

soluntion3
bool GetNodePath(TreeNode * pRoot, TreeNode * pNode, list<TreeNode *> &path) {
    if (pRoot == pNode) 
        return true;
    path.push_back(pRoot);
    bool found = false;
    vector<TreeNode *>::iterator i = pRoot->children.begin();
    while (! found && i < pRoot->children.end()) {
        found = GetNodePath(*i, pNode, path);
        i ++;
    }
    if (! found) 
        path.pop_back();
    return found;
}

TreeNode * GetLastCommonNode(const list<TreeNode*> &path1, const list<TreeNode*> &path2) {
    list<TreeNode*>::const_iterator iterator1 = path1.begin();
    list<TreeNode*>::const_iterator iterator2 = path2.begin();
    TreeNode* pLast = NULL;
    while (iterator1 != path1.end() && iterator2 != path2.end()) {
        if (*iterator1 == *iterator2)
            pLast = *iterator1;
        iterator1 ++;
        iterator2 ++;
    }
    return pLast;
}

TreeNode * GetLastCommonParent(TreeNode * pRoot, TreeNode * pNode1, TreeNode * pNode2) {
    if (pRoot == NULL || pNode1 == NULL || pNode2 == NULL)
        return NULL;
    List<TreeNode *> path1;
    GetNodePath(pRoot, pNode1, path1);
    List<TreeNode *> path2;
    GetNodePath(pRoot, pNode2, path2);
    return GetLastCommonNode(path1, path2);
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容