剑指offer11-20

11题目描述

二进制中1的个数:

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

思路

首先要明白几个常识 1.计算机中整数都是以补码存储,所以此题不需考虑正负问题 2.按位与操作&要熟悉。

题解思路:如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。 举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。

代码

class Solution {
public:
     int  NumberOf1(int n) 
     {
         int count = 0;
         while(n != 0)
         {
             count++;
             n = n & (n - 1);
         }
         return count;
     }
};

12题目描述

数值的整数次方:

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

保证base和exponent不同时为0

思路

本题看题解 如果不用pow函数则需要充分考虑base exponent的各种极端情况, 我使用了pow函数,直接ac了。。

代码

class Solution {
public:
    double Power(double base, int exponent) {
        //if(base == 0) return 0.0;
        //if(exponent == 0) return 1.0;
        return pow(base, exponent);
    }
};

13题目描述

调整数组顺序使奇数位于偶数前面:

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

思路1

采用最暴力的方法,类似冒泡排序,两个循环,相邻两个数进行对比,如果前面为偶数后面为奇数 则两者互换。

代码

class Solution 
{
public:
    void reOrderArray(vector<int> &array) 
    {
        for(int i = 0; i < array.size(); i++)
        {
            for(int j = 0; j < array.size(); j++)
            {
                if(((array[j] % 2) == 0) && (array[j + 1] % 2) == 1)
                {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
                else continue;
            }
        }
    }
};

思路2

再创建一个数组,遇见偶数就存入,同时在原数组中删除,最后再存入原数组中。这里主要熟悉vector迭代器的使用。

代码

class Solution{
public:
    void reOrderArray(vector<int> &array) {
 
        vector<int> array_temp;
        vector<int>::iterator ib1, ie1;
        ib1 = array.begin();
 
 
        for (; ib1 != array.end();){            //遇见偶数,就保存到新数组,同时从原数组中删除
            if (*ib1 % 2 == 0) {
                array_temp.push_back(*ib1);
                ib1 = array.erase(ib1);
            }
            else{
                ib1++;
            }
 
        }
        vector<int>::iterator ib2, ie2;
        ib2 = array_temp.begin();
        ie2 = array_temp.end();
 
        for (; ib2 != ie2; ib2++)             //将新数组的数添加到老数组
        {
            array.push_back(*ib2);
        }
    }
};

14题目描述

链表中倒数第k个结点:

输入一个链表,输出该链表中倒数第k个结点。

思路

首先计算出链表长度,新建一个指针指向表头,然后向后遍历到length - k的结点就可以。思路比较简单,此题主要是特殊情况的判断,对于原链表和K的判断一定要考虑全面。

代码

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) 
    {
        if(pListHead == NULL || k <= 0)
            return NULL;
        int length = 0;
        ListNode* pre = pListHead;
        while(pListHead != NULL)
        {
            pListHead = pListHead -> next;
            length++;
        }
        if(k > length) return NULL;
        for(int i = 0; i < length - k; i++)
        {
            pre = pre -> next;
        }
        return pre;
    }
};

15题目描述

反转链表:

输入一个链表,反转链表后,输出新链表的表头。

思路

很普通的反转链表,卡了好长时间,才发现是判断的==没补全。。。。还是要注意一些细节

代码

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) 
    {
        if(pHead == NULL) return pHead;
        ListNode* now = pHead;
        ListNode* pre = NULL;
        ListNode* next = NULL;
        while(now != NULL)
        {
            next = now -> next;
            now -> next = pre;
            pre = now;
            now = next;
        }
        return pre;
    }
};

16题目描述

合并两个排序的链表:

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

思路

本题最好不要在原始链表上进行操作而是新建一个链表,两两比较,小的加入到新链表末尾,这是最方便的做法。 还有第二种思路是递归,不太容易想到,明白即可。

代码

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        //if(pHead1 == NULL && pHead2 == NULL) return NULL;
        //if(pHead1 == NULL && pHead2 != NULL) return pHead2;
        //if(pHead1 != NULL && pHead2 == NULL) return pHead1;
        ListNode* new_head = new ListNode(1);
        ListNode* head = new_head;
        ListNode* cur = new_head;
        while(pHead1 != NULL && pHead2 != NULL)
        {
            if(pHead1 -> val <= pHead2 -> val)
            {
                cur -> next = pHead1;
                cur = cur -> next;
                pHead1 = pHead1 -> next;
            }
            else
            {
                cur -> next = pHead2;
                cur = cur -> next;
                pHead2 = pHead2 -> next;
            }
        }
        if(pHead1 != NULL) cur -> next = pHead1;
        if(pHead2 != NULL) cur -> next = pHead2;
        return head -> next;
    }
};

17题目描述

树的子结构:

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路

明显使用递归,这里需要使用两个递归来完成此任务,一个递归负责向下递推树1,第二个递归负责判断从此开始的树1子树与树2是否相同。

代码

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if(pRoot1 == NULL || pRoot2 == NULL) return false;
        if(pRoot1 -> val == pRoot2 -> val)
        {
            if(IsSubtree(pRoot1, pRoot2)) return true;
        }
        return HasSubtree(pRoot1 -> left, pRoot2) || HasSubtree(pRoot1 -> right, pRoot2);
    }
    
    bool IsSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if(pRoot2 == NULL) return true;
        if(pRoot1 == NULL) return false;
        if(pRoot1 -> val != pRoot2 -> val) return false;
        return (IsSubtree(pRoot1 -> left, pRoot2 -> left) && IsSubtree(pRoot1 -> right, pRoot2 -> right));
    }
};

18题目描述

二叉树的镜像:

操作给定的二叉树,将其变换为源二叉树的镜像。

思路

采用递归,这里为了避免太多判断,重点在于进行递归出口的判断(为空),然后进行递归即可。

代码

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    void Mirror(TreeNode *pRoot) 
    {
        if(pRoot == NULL) return;
        if(pRoot -> left == NULL && pRoot -> right == NULL) return;
        TreeNode* temp = NULL;
        temp = pRoot -> left;
        pRoot -> left = pRoot -> right;
        pRoot -> right = temp;
        Mirror(pRoot -> left);
        Mirror(pRoot -> right);
    }
};

19题目描述

顺时针打印矩阵:

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

思路

这个题说实话还挺难的,用自己的思路没做出来,采用了一个最清晰易懂的思路:首先模拟矩阵,找规律,发现设置好四个变量后每一圈对于一个方向都是相同的。设置4个变量,分别代表目前的上下左右情况,遍历完一圈后算作一次loop,上下左右都往内部缩一圈。这其中比较难想到的是特殊情况:矩阵为单独一列或者单独一行,要想让此case通过必须在第三四个循环上加上判断。

代码

class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
        vector<int> printM;
        if(matrix.empty() || matrix[0].empty()) return printM;
        int rows = matrix.size();
        int colomns = matrix[0].size();
        int top = 0, left = 0, bottom = rows - 1, right = colomns - 1;
        while(top <= bottom && left <= right)
        {
            for(int i = left; i <= right; i++)
                printM.push_back(matrix[top][i]);
            for(int i = top + 1; i <= bottom; i++)
                printM.push_back(matrix[i][right]);
            if(top < bottom)
            {
                for(int i = right - 1; i >= left; i--)
                    printM.push_back(matrix[bottom][i]);
            }
            if(left < right)
            {
                for(int i = bottom - 1; i > top; i--)
                    printM.push_back(matrix[i][left]);
            }
            top++, left++, bottom--, right--;
        }
        return printM;
    }
};

20题目描述

包含min函数的栈:

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。 注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。

思路

使用两个栈,一个存放模拟真实的栈,第二个栈用来存放最小数,当新压入的数小于等于最小时压入第二个栈,此时要注意pop时,如果pop的是最小数,同样要在第二个栈中pop出。

代码

class Solution {
public:
    stack<int> s;
    stack<int> min_s;
    void push(int value) {
        s.push(value);
        if(min_s.empty()) min_s.push(value);
        if(!min_s.empty())
            if(value <= min_s.top())
                min_s.push(value);
    }
    void pop() {
        if(s.top() == min_s.top())
        {
            s.pop();
            min_s.pop();
        }
        else
            s.pop();
    }
    int top() {
        return s.top();
    }
    int min() {
        return min_s.top();
    }
};
comments powered by Disqus
Copyright © 2024 RainPot