剑指offer30天打卡活动(day21 - day26)

目录

day21:

一. 剑指 Offer 15. 二进制中 1 的个数

二. 剑指 Offer 65. 不用加减乘除做加法

day22:

一. 剑指 Offer 56 - I. 数组中数字出现的次数

二. 剑指 Offer 56 - II. 数组中数字出现的次数 II

day23:

一. 剑指 Offer 39. 数组中出现次数超过一半的数字

二. 剑指 Offer 66. 构建乘积数组

day24:

一. 剑指 Offer 14- I. 剪绳子

二. 剑指 Offer 57 - II. 和为 s 的连续正数序列

三. 剑指 Offer 62. 圆圈中最后剩下的数字

day25:

一. 剑指 Offer 29. 顺时针打印矩阵

二. 剑指 Offer 31. 栈的压入、弹出序列

day26:

一. 剑指 Offer 20. 表示数值的字符串

二. 剑指 Offer 67. 把字符串转换成整数


day21:

一. 剑指 Offer 15. 二进制中 1 的个数

题目:

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数。

示例:

输入:n = 11 (控制台输入 00000000000000000000000000001011)

输出:3

解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。

解题思路: 

设 n 为二进制数,根据与运算的定义可得:

  • n & 1 = 0,二进制 n 最右边以为为 0;
  • n & 1 = 1,二进制 n 最右边以为为 1。

每判断一次若结果为 1 则对 计数器+1,并且将 n 右移一位。

C++代码:

class Solution {
public:
    int hammingWeight(uint32_t n) {
        unsigned int res = 0;
        while(n)
        {
            res += n & 1;
            n >>= 1;
        }
        return res;
    }
};

二. 剑指 Offer 65. 不用加减乘除做加法

题目:

写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。

示例:

输入:a = 1, b = 1

输出:2

解题思路: 

由于无进位和 与 异或运算 规律相同,进位 和 与运算 规律相同(并需左移一位),可得:

  • n = a ^ b        (无进位的和)
  • c = a&b << 1  (进位)

所以a + b = n +c ,循环求 n 和 c ,直到进位c = 0,最终 a+b = n。

C++代码:

class Solution {
public:
    int add(int a, int b) {
        while(b)
        {
            int c = (unsigned)(a & b) << 1;
            a ^= b;
            b = c;
        }

        return a;
    }
};

day22:

一. 剑指 Offer 56 - I. 数组中数字出现的次数

题目:

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例:

输入:nums = [4,1,4,6]

输出:[1,6] 或 [6,1]

解题思路: 

位运算(或者哈希表)

C++代码:

class Solution {
public:
    vector singleNumbers(vector& nums) {
        int n = 0;
        for(int i = 0; i < nums.size(); i++)
            n ^= nums[i];
        
        int m = 1;
        while((m & n) == 0)
            m <<= 1;
        
        int x = 0;
        int y = 0;
        for(int i = 0; i < nums.size(); i++)
        {
            if(nums[i] & m) x ^= nums[i];
            else y ^= nums[i];
        }
        return {x, y};
    }
};

二. 剑指 Offer 56 - II. 数组中数字出现的次数 II

题目:

在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。

示例:

输入:nums = [3,4,3,3]

输出:4

解题思路: 

位运算(或者哈希表)

C++代码:

class Solution {
public:
    int singleNumber(vector& nums) {
        int counts[32] = {0};
        for(int i = 0; i < nums.size(); i++)
        {
            for(int j = 0; j < 32; j++)
            {
                counts[j] += nums[i] & 1;
                nums[i] >>= 1;
            }
        }

        int res = 0;
        for(int i = 31; i >= 0; i--)
        {
            res <<= 1;
            res |= counts[i] % 3;
        }

        return res;
    }
};

day23:

一. 剑指 Offer 39. 数组中出现次数超过一半的数字

题目:

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

示例:

输入:[1, 2, 3, 2, 2, 2, 5, 4, 2]

输出:2

解题思路一: 

排序

C++代码:

class Solution {
public:
    int majorityElement(vector& nums) {
        sort(nums.begin(), nums.end());
        int k = nums.size();
        return nums[(k-1)/2];
    }
};

解题思路二: 

摩尔投票法

C++代码:

class Solution {
public:
    int majorityElement(vector& nums) {
        int vector = 0;
        int k = 0;
        for(int i = 0; i < nums.size(); i++)
        {
            if(vector == 0) k = nums[i];
            vector += (nums[i] == k ? 1:-1);
        }
        return k;
    }
};

二. 剑指 Offer 66. 构建乘积数组

题目:

给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B[i] 的值是数组 A 中除了下标 i 以外的元素的积, 即 B[i]=A[0] × A[1] × … × A[i-1] × A[i+1] × … × A[n-1]。不能使用除法。

示例:

输入:[1,2,3,4,5]

输出:[120,60,40,30,24]

C++代码:

class Solution {
public:
    vector constructArr(vector& a) {
        if(a.size() == 0) return {};
        vector b(a.size(), 1);
        b[0] = 1;
        for(int i = 1; i < a.size(); i++)
        {
            b[i] = b[i-1] * a[i-1];
        }

        int mul = 1;
        for(int i = a.size()-2; i >= 0; i--)
        {
            mul *= a[i+1];
            b[i] *= mul;
        }

        return b;
    }
};

day24:

一. 剑指 Offer 14- I. 剪绳子

题目:

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

示例:

输入:2

输出:1

解释:2 = 1 + 1, 1 × 1 = 1

解题思路: 

数学知识:

推论一: 将绳子 以相等的长度等分为多段 ,得到的乘积最大。

推论二: 尽可能将绳子以长度 3 等分为多段时,乘积最大。

C++代码:

class Solution {
public:
    int cuttingRope(int n) {
        if(n <= 3) return n-1;
        int cnt = n % 3, k = n / 3;
        if(cnt == 0) return pow(3, k);
        if(cnt == 1) return pow(3, k-1)*4;
        return pow(3, k)*2;
    }
};

二. 剑指 Offer 57 - II. 和为 s 的连续正数序列

题目:

输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。

序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

示例:

输入:target = 9

输出:[[2,3,4],[4,5]]

解题思路: 

双指针

C++代码:

class Solution {
public:
    vector> findContinuousSequence(int target) {
        int i = 1, j = 2, sum = 3;
        vector> res;

        while(i < j)
        {
            if(sum == target)
            {
                vector temp;
                for(int k = i; k <= j; k++)
                {
                    temp.push_back(k);
                }
                res.push_back(temp);
            }
            
            if(sum < target)
            {
                j++;
                sum += j;
            }
            else
            {
                sum -= i;
                i++;
            }
            
        }

        return res;
    }
};

三. 剑指 Offer 62. 圆圈中最后剩下的数字

题目:

0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

示例:

输入:n = 5, m = 3

输出:3

解题思路: 

“约瑟夫环” 问题:

F[n] = ( F[n-1] + m ) % n 

C++代码:

class Solution {
public:
    int lastRemaining(int n, int m) {
        return dfs(n, m);
    }

private:
    int dfs(int n, int m)
    {
        if(n == 1)
            return 0;
        else
            return (dfs(n-1, m) + m) % n;
    }
};

day25:

一. 剑指 Offer 29. 顺时针打印矩阵

题目:

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

示例:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]

输出:[1,2,3,6,9,8,7,4,5]

C++代码:

class Solution {
public:
    vector spiralOrder(vector>& matrix) {
        if (matrix.empty()) return {};
        vector res;
        int l = 0, r = matrix[0].size() - 1; 
        int t = 0, b = matrix.size() - 1;
        while(true)
        {
            //从左向右
            for(int i = l; i <= r; i++) res.push_back(matrix[t][i]);
            if(++t > b) break;
            //从上向下
            for(int i = t; i <= b; i++) res.push_back(matrix[i][r]);
            if(--r < l) break;
            //从右向左
            for(int i = r; i >= l; i--) res.push_back(matrix[b][i]);
            if(--b < t) break;
            //从下向上
            for(int i = b; i >= t; i--) res.push_back(matrix[i][l]);
            if(++l > r) break;
        }

        return res;
    }
};

二. 剑指 Offer 31. 栈的压入、弹出序列

题目:

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

示例:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]

输出:true

解题思路: 

利用栈的特性: 每次入栈后,循环判断 “栈顶元素 == 弹出序列的当前元素” 是否成立,将符合弹出序列顺序的栈顶元素全部弹出。

C++代码:

class Solution {
public:
    bool validateStackSequences(vector& pushed, vector& popped) {
        stack res;
        int i = 0;
        for(auto num: pushed)
        {
            res.push(num);
            while(!res.empty() && res.top() == popped[i])
            {
                res.pop();
                i++;
            }
        }
        return res.empty();
    }
};

day26:

一. 剑指 Offer 20. 表示数值的字符串

题目:

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。

示例:

输入:s = "0"

输出:true

C++代码:

class Solution {
public:
    bool isNumber(string s) {

        int i = 0;
        while (s[i] == ' ')
            i++;

        if (s[i] == '+' || s[i] == '-')
            i++;

        //记录是否存在字符'.'
        bool res = false;
        if(s[i] == '.')
        {
            res = true;
            i++;
        }

        if(s[i] < '0' || s[i] > '9')
            return false;
        
        while(s[i] >= '0' && s[i] <= '9')
            i++;

        if(s[i] == '.')
        {
            if(res)
                return false;
            else
            {
                i++;
                while(s[i] >= '0' && s[i] <= '9')
                    i++;
            }
        }

        if(s[i] == 'e' || s[i] == 'E')
        {
            i++;
            if (s[i] == '+' || s[i] == '-')
                i++;

            if(s[i] < '0' || s[i] > '9')
                return false;

             while(s[i] >= '0' && s[i] <= '9')
                    i++;
        }

        while(s[i] == ' ')
            i++;

        if(s[i] == '\0')
            return true;
        else
            return false;
        
    }
};

二. 剑指 Offer 67. 把字符串转换成整数

题目:

写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。

示例:

输入:"42"

输出:42

C++代码:

class Solution {
public:
    int strToInt(string str) {
        int insize = INT_MAX / 10;
        int i = 0, len = str.size();
        int res = 0;
        //标记遇到的第一个数字是'+' 或 '-'
        int sign = 1;
        

        //当数组中没有元素时返回0
        if(len == 0) return 0;
        //当数组中元素全部是空格时返回0
        while(str[i] == ' ')
        {
            if(++i == len) return 0;
        }

        if(str[i] == '-') sign = -1;
        if(str[i] == '+' || str[i] == '-') i++;

        for(int j = i; j < len; j++)
        {
            if(str[j] < '0' || str[j] > '9') break;
            if(res > insize || (res == insize && str[j] > '7'))
                return sign == 1 ? INT_MAX:INT_MIN;
            res = res * 10 + (str[j] - '0'); 
        }

        return sign * res;
    }
};

 题目源自:

leetcode图解算法数据结构

你可能感兴趣的:(算法,数据结构,c++)