编程题:2020-08-16

###########################################################

记忆点:位运算。n&(n-1)求多少个1、判断2的幂等价于只存在1个“1”

题目描述
编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。

输入描述:
输入一个整数(int类型)

输出描述:
这个数转换成2进制后,输出1的个数

示例1
输入

5
输出

2

#include <iostream>
using namespace std;
int main()
{
  int input, mask, res = 0;
  cin >> input;
  while(input){
    mask = input - 1;
    input &= mask;
    res += 1;
    
  }
  cout << res;
  
  return 0;
}

题目描述
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
等价于判断该数是否只存在一个“1”

int main()
{
  int input;
  cin >> input;
  // 位运算1次,抹掉最右边的1,若还不为0,说明不是2的幂
  if(input & (input-1) > 0) return false;
  return true;

}

给定一个整数,编写一个算法将这个数转换为十六进制数。对于负整数,我们通常使用 补码运算 方法。

注意:

十六进制中所有字母(a-f)都必须是小写。
十六进制字符串中不能包含多余的前导零。如果要转化的数为0,那么以单个字符’0’来表示;对于其他情况,十六进制字符串中的第一个字符将不会是0字符。
给定的数确保在32位有符号整数范围内。
不能使用任何由库提供的将数字直接转换或格式化为十六进制的方法。
输入:
-1

输出:
“ffffffff”

class Solution {
public:
    string toHex(int num) {
        string r = ""; int p = -1;
        string hex[16]={"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
        if (num == 0) return "0";
        else if (num <0) p=8;
        while (num) {
            if (p == 0) break;
            int c = 0;
            c = (num & 0x0000000f);
            r = hex[c] + r;
            num >>= 4;
            --p;
        }
        return r;
    }
};

记忆点:排序容器,基于范围的for循环

题目描述

给定n个字符串,请对n个字符串按照字典序排列。
输入描述:
输入第一行为一个正整数n(1≤n≤1000),下面n行为n个字符串(字符串长度≤100),字符串中只含有大小写字母。
输出描述:
数据输出n行,输出结果为按照字典序排列的字符串。
示例1
输入

9
cap
to
cat
card
two
too
up
boat
boot
输出

boat
boot
cap
card
cat
to
too
two
up

#include <iostream>
#include <set>
#include <string>
using namespace std;
int main()
{
  int n;
  string tmp;
  multiset<string> strings;
  
  cin >> n;
  for (int i = 0; i < n; ++i){
    cin >> tmp;
    strings.insert(tmp);
  }
  for(auto s:strings){
    cout << s << endl;
  }
  return 0;
}

###########################################################

记忆点:浮点到整型取整,数据类型转换方法

题目描述
写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于5,向上取整;小于5,则向下取整。

输入描述:
输入一个正浮点数值

输出描述:
输出该数值的近似整数值

示例1
输入

5.5
输出

6

#include <iostream>

using namespace std;

int main()
{
  double input;
  cin >> input;
  cout << static_cast<int>(input + 0.5) << endl;
  return 0;
  
}

###########################################################

记忆点:reverse(first,last)数组逆序方法,getline(cin, str);行输入方法

题目描述
将一个字符串str的内容颠倒过来,并输出。str的长度不超过100个字符。 如:输入“I am a student”,输出“tneduts a ma I”。

输入参数:

inputString:输入的字符串

返回值:

输出转换好的逆序字符串

输入描述:
输入一个字符串,可以有空格

输出描述:
输出逆序的字符串

示例1
输入

I am a student
输出

tneduts a ma I

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
  string str;
  // 因为空格会干扰 >> 运算,使用getline(cin, str)取代
  getline(cin, str);
  //cin >> input;
  reverse(str.begin(), str.end());
  cout << str << endl;
  
  return 0;
}

###########################################################

记忆点:循环检测输入多个case,while(getline(cin, s))

题目描述
密码按如下规则进行计分,并根据不同的得分为密码进行安全等级划分。

一、密码长度:

5 分: 小于等于4 个字符

10 分: 5 到7 字符

25 分: 大于等于8 个字符

二、字母:

0 分: 没有字母

10 分: 全都是小(大)写字母

20 分: 大小写混合字母

三、数字:

0 分: 没有数字

10 分: 1 个数字

20 分: 大于1 个数字

四、符号:

0 分: 没有符号

10 分: 1 个符号

25 分: 大于1 个符号

五、奖励:

2 分: 字母和数字

3 分: 字母、数字和符号

5 分: 大小写字母、数字和符号

最后的评分标准:

= 90: 非常安全

= 80: 安全(Secure)

= 70: 非常强

= 60: 强(Strong)

= 50: 一般(Average)

= 25: 弱(Weak)

= 0: 非常弱

对应输出为:

VERY_SECURE

SECURE,

VERY_STRONG,

STRONG,

AVERAGE,

WEAK,

VERY_WEAK,

请根据输入的密码字符串,进行安全评定。

注:

字母:a-z, A-Z

数字:-9

符号包含如下: (ASCII码表可以在UltraEdit的菜单view->ASCII Table查看)

!"#$%&’()*+,-./ (ASCII码:x21~0x2F)

:;<=>?@ (ASCII<=><=><=><=><=>码:x3A~0x40)

[]^_` (ASCII码:x5B~0x60)

{|}~ (ASCII码:x7B~0x7E)

接口描述:

Input Param
String pPasswordStr: 密码,以字符串方式存放。

Return Value
根据规则评定的安全等级。

输入描述:
输入一个string的密码

输出描述:
输出密码等级

示例1
输入

38$@NoNoNo
输出

VERY_SECURE

#include <iostream>
#include <string>
#include <vector>
using namespace std;
//接口一、密码长度:5 分: 小于等于4 个字符;10 分: 5 到7 字符;25 分: 大于等于8 个字符
int Password_Length_Score(int len)
{
  if(len <= 4){
    return 5;
  }
  else if(len <= 7){
    return 10;
  }
  return 25;
}
int Alphabet_Score(string s)
{
  int score = 0;
  int num1 = 0; //大写字母个数
  int num2 = 0; //小写字母个数
  int num3 = 0;  //数字个数
  int num4 = 0;  //符号个数
    for (char c : s)
    {
      if (c >= 65 && c <= 90)
        num1 += 1;
      else if (c >= 97 && c <= 122)
        num2 += 1;
      else if (c >= 0x30 && c <= 0x39)
        num3 += 1;
      else if (c >= 0x21 && c <= 0x2f)
        num4 += 1;
      else if (c >= 0x3a&& c <= 0x40)
        num4 += 1;
      else if (c >= 0x5b && c <= 0x60)
        num4 += 1;
      else if (c >= 0x7b && c <= 0x7e)
        num4 += 1;
    }
	if (num1)
		score += 10;
	if (num2)
		score += 10;
    if (num3){
      score += 10;
      if (num3 > 1) score += 10;//2个数字奖励
    }
    if (num4){
      score += 10;
      if (num4 > 1) score += 15;//2个符号奖励
    }
    if (num1 && num2 && num3 && num4) score += 5;
    else if (num1 || num2 && num3 && num4) score += 3;
    else if (num1 || num2 && num3) score += 2;
	return score;
}
int getScoreLevel(int score)
{
  if (score >= 90) return 0;
  if (score >= 80) return 1;
  if (score >= 70) return 2;
  if (score >= 60) return 3;
  if (score >= 50) return 4;
  if (score >= 25) return 5;
  if (score >= 0) return 6;
  
}
int main()
{
  string s;
  vector<string> output = {"VERY_SECURE", "SECURE", "VERY_STRONG",
                         "STRONG", "AVERAGE", "WEAK", "VERY_WEAK"};
    int score, index;
    while (getline(cin, s))
    {
      score = Alphabet_Score(s) + Password_Length_Score(s.size());
      index = getScoreLevel(score);
      cout << output.at(index) << endl;
    }
  return 0;
}

###########################################################

记忆点:最长回文串长度,动态规划

动态规划与回文串原理
题目描述
Catcher 是MCA国的情报员,他工作时发现敌国会用一些对称的密码进行通信,比如像这些ABBA,ABA,A,123321,但是他们有时会在开始或结束时加入一些无关的字符以防止别国破解。比如进行下列变化 ABBA->12ABBA,ABA->ABAKK,123321->51233214 。因为截获的串太长了,而且存在多种可能的情况(abaaab可看作是aba,或baaab的加密形式),Cathcer的工作量实在是太大了,他只能向电脑高手求助,你能帮Catcher找出最长的有效密码串吗?

(注意:记得加上while处理多个测试用例)

输入描述:
输入一个字符串

输出描述:
返回有效密码串的最大长度,等价于求最长回文字串长度
动态规划与回文串原理
示例1
输入

ABBA
输出

4

//本题等价于求最长回文字串长度
#include<iostream> 
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
    string instr;
    while (getline(cin, instr))
    {
        int len = instr.length();
        int res = 1;             //即使没有回文串,那一个字符也算是回文串
        string tempstr = instr;      //复制原字符串,并反转。
        reverse(tempstr.begin(), tempstr.end());
 		// 创建二维向量
        vector<vector<int>> dp(len + 1, vector<int>(len + 1, 0));
        for (int i = 1; i <= len; i++)
        {
            for (int j = 1; j <= len; j++)
            {
                if (tempstr[i] == instr[j])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                res = max(res, dp[i][j]);    //每次都取最大的,保证记录的是最长回文串长度
            }
        }
        cout << res << endl;
    }
 
    return 0;
}

###########################################################

记忆点:循环检查输入while(cin >> num),迭代器的 ±><

输入描述:
首先输入数字n,表示要输入多少个字符串。连续输入字符串(输出次数为N,字符串长度小于100)。

输出描述:
按长度为8拆分每个字符串后输出到新的字符串数组,长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。

示例1
输入
复制
2
abc
123456789
输出
复制
abc00000
12345678
90000000

#include <iostream>
#include <string>
#include <vector>
using namespace std;

// 字符串小于限制,填充0,返回填充后的结果
string  FillStr(string strValue)
{
  if(strValue.size() >= 8) return strValue;
  for(int i = 8 - strValue.size(); i > 0; i--)
  {
    strValue.push_back('0');
  }
  return strValue;
}
// 字符串大于限制,分割字符串并且推入结果列表
int seprateStr(vector<string> &vecStrResult, string& strValue)
{
  int retNum = 1;
  string::iterator it = strValue.begin();
  while(strValue.end() - it > 8)
  {
    vecStrResult.push_back(string(it, it + 8));
    it += 8;
    retNum += 1;
  }
  if(strValue.end() - it > 0)
    vecStrResult.push_back(FillStr(string(it, strValue.end())));
  return retNum;
}
// 把输入的单个字符串添加到结果字串列表里面
int  AddString(vector<string> &vecStrResult, string& strValue)
{
  if(strValue.empty()) return 0;
  // 检查字符串的长度,调用不同的处理方法
  if(strValue.size() < 8) vecStrResult.push_back(FillStr(strValue));
  else if(strValue.size() > 8) seprateStr(vecStrResult, strValue);
  else if(strValue.size() == 8) vecStrResult.push_back(strValue);
  return 1;
}

int main()
{
  int num;
  string strTmp;
  // 循环输入检查,可输入多个case
  while(cin >> num)
  {
    vector<string> vecStrResult;
    // 添加字符串
    while(num)
    {
      cin >> strTmp;
      AddString(vecStrResult, strTmp);
      num -= 1;
    }
    // 打印字符串
    for(auto s:vecStrResult)
    {
      cout << s << endl;
    }
  }

  return 0;
}

########################################################################################

记忆点:queue队列、set判重

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。

#include <iostream>
#include <string>
#include <set>
#include <queue>
using namespace std;
class Solution
{
public:
  //Insert one char from stringstream
    void Insert(char ch)
    {
      // 如果找不到重复的,说明是第一次出现
      if(++arrInput[int(ch)] < 2)
      {
        qInput.push(ch);
      }
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce()
    {
      if(qInput.empty()) return '#';
      while(arrInput[int(qInput.front())] > 1)
      {
        qInput.pop();
      }
      return qInput.empty() ? '#' : qInput.front();
    }
private:

  char arrInput[255] = {};
  queue<char> qInput;
};

记忆点:重构二叉树,在递归传递时要使用全局数组变量。

犯过的错:拿全局的数组索引(map),匹配切片后的数组,造成越界!
注意点:

  • 如果要使用切片后的数组作为参数传入,则不需要提前map,而应该每次传入数组后,再去遍历寻找root结点;
  • 如果想提前map,则递归过程中,都得使用全局数组!

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

  • 由于使用了map加快寻找root,所以每次传入的数组必须是全局数组,并附带左右指针来划分这个全局数组的区间
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    // 因为遍历结果中没有重复的数字,所以可以用map来映射value与index
    map<int,int> map1;
    TreeNode* rebuild(vector<int>& pre, int pre_left, int pre_right, vector<int>& vin, int vin_left, int vin_right){
      if((pre_left >= pre_right) || (vin_left >= vin_right)) return NULL;
      TreeNode* root = new TreeNode(pre[pre_left]);
      // 借助map找出root在中序遍历中的位置。num也代表左子树的节点数目。
      int vin_root_index = map1[pre[pre_left]];
      // 计算root左侧的左子树结点数量
      int num = vin_root_index - vin_left;
      // 为全局数组划分区间,左闭右开
      root->left = rebuild(pre, pre_left+1, pre_left+1+num, vin, vin_left, vin_root_index);
      root->right = rebuild(pre, pre_left+1+num, pre_right, vin, vin_root_index+1, vin_right);
      return root;
  }
  TreeNode* reConstructBinaryTree(vector<int> p,vector<int> v) {
    if(p.size() < 1 || v.size() < 1) return NULL;
    // 把value映射到index
    for(int i = 0; i < v.size(); i++){
      map1[v[i]] = i;
    }
    return rebuild(p, 0, p.size(), v, 0, v.size());

  }
};

记忆点:in-place算法,冒泡法

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

//两个思路吧,第一个思路:类似冒泡算法,前偶后奇数就交换:
class Solution {
public:
    void reOrderArray(vector<int> &array) 
    {
    // 用i从左向右遍历整个数组
        for (int i = 0; i < array.size();i++)
        {	// 用j从右向左遍历,遇到奇数则交换位置。
        	// 有序数列是从左向右生长
            for (int j = array.size() - 1; j>i;j--)
            {
                if (array[j] % 2 == 1 && array[j - 1]%2 == 0) //前偶后奇交换
                {
                    swap(array[j], array[j-1]);
                }
            }
        }
    }
};
 
//第二个思路:再创建一个数组
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);
        }
    }
};

记忆点:矩阵的顺时针打印(整个矩阵用一个while,四条边用4个for,第三边和第四边需要避免重复)

题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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.

class Solution {
public:
    vector<int> printMatrix(vector<vector<int>> matrix) {
      int n = 0, cnt = matrix.size()*matrix[0].size();
      int high = matrix.size() - 1,low = 0,left = 0,right = matrix[0].size() - 1;
      vector<int> result;
      // 整个矩阵用1个while遍历
      while(low <= high && left <= right){
        // 从左向右
        for(int col = left; col <= right; col++){
          result.push_back(matrix[low][col]);
        }
        // 从上到下
        for(int row = low + 1; row <= high; row++){
          result.push_back(matrix[row][right]);
        }
        // 如果最后的矩阵只是一行或一列,那么走完半圈就没了,下面增加条件判断避免重复
        // 从右到左
        if(low < high){
          for(int col = right - 1; col >= left; col--){
            result.push_back(matrix[high][col]);
          }
        }
        // 从下到上
        if(left < right){
          for(int row = high - 1; row >= low + 1; row--){
            result.push_back(matrix[row][left]);
          }
        }
        // 一圈走完,缩进1个单位
        low++;
        high--;
        left++;
        right--;
      }
      return result;
    }
};

记忆点:求质因子的过程是从2自增到num

功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如180的质因子为2 2 3 3 5 )

最后一个数后面也要有空格

输入描述:
输入一个long型整数

输出描述:
按照从小到大的顺序输出它的所有质数的因子,以空格隔开。最后一个数后面也要有空格。

示例1
输入180
输出2 2 3 3 5

分解质因数代码: 将一个正整数分解质因数。例如:输入n=90,打印出90=233*5。
程序分析:对n进行分解质因数,应先找到一个最小的质数k,然后按下述步骤完成:
(1)如果这个质数恰等于n,则说明分解质因数的过程已经结束,打印出即可。
(2)如果n>k,但n能被k整除,则应打印出k的值(k为质因子);并用n除以k的商,作为新的正整数你n;同时k++  重复执行第一步。
(3)如果n不能被k整除,则用k++,重复执行第一步。

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main(void){
    long num;
    int i;
    while(cin >> num){
        for(i = 2; i < num; i++){
            while(num%i == 0){
                cout << i << ' ';
                num = num/i;
            }
        }
        if(i == num) cout << i << ' ';
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值