2021-11-17每日刷题打卡

2021-11-17每日刷题打卡

力扣——每日一题

318. 最大单词长度乘积

给定一个字符串数组 words,找到 length(word[i]) * length(word[j]) 的最大值,并且这两个单词不含有公共字母。你可以认为每个单词只包含小写字母。如果不存在这样的两个单词,返回 0。

示例 1:

输入: [“abcw”,“baz”,“foo”,“bar”,“xtfn”,“abcdef”]
输出: 16
解释: 这两个单词为 “abcw”, “xtfn”。

这题我用了两个方法,第一个是几分钟前还不会位运算的本笨比写的暴力方法,第二个是稍稍学习了下位运算的聪明的笨比写的较轻松的方法。

第一个:准备一个以map容器为元素的vector容器v(即vector<map<char,int>>),还有一个数max来存最大值(初始化为0),遍历words数组,把各个单词的组成情况用map<char,int>容器存储起来插入到v中,等所有的单词都遍历完后开始下一轮遍历,遍历v容器,先拿第一个元素和剩下所有元素比较,再拿第二个元素和剩下所有元素比较…………以此往复,(比较方式是用for遍历26个字母,因为前面我们用map存下了各个单词的组成状况,所以这里我们用,map[‘a’]或map[‘b’]这样的方式就可以知道这字母的数为多少,假如一个单词为look,那么map[l]=1,map[o]=2,如果没有这个字母那就是为0,比如map[a]=0……)。然后我们比较同时比较两个单词的组成情况,判断一下有没有出现map1[]!=0&&map2[]!=0的情况,如果有就说明这两个单词有重复的字母,不满足条件,我们直接去比较下一对。如果对比结束了发现没有重复的字母,那我们把两个单词的长度相乘,和max对比,大于max就把乘积赋给max,小于则不管。最后一切遍历结束后返回max即可。

class Solution {
public:
    int maxProduct(vector<string>& words) {
        vector<unordered_map<char, int>>v;
        int max_len = 0;
        for (auto i : words)
        {
            unordered_map<char, int>mymap;
            for (auto j : i)
                mymap[j]++;
            v.push_back(mymap);
        }
        int n = v.size(), l = 0, r = 1;
        bool flag = true;
        while(l<n)
        {
            r=0;
            while (r < n)
            {
                
                for (char i = 'a'; i <= 'z'; i++)
                {
                    if (v[l][i] != 0 && v[r][i] != 0)
                    {
                        flag = false;
                        break;
                    }
                }
                int num =  words[l].size() * words[r].size();
                if (flag)
                    max_len = max(max_len,num);
                flag = true;
                r++;
            }
            l++;
        }
        return max_len;
    }
};

第二个是位运算,上面的方法我们是分析了一个单词的组成,比方拿look来说是有一个l、两个o、三个k组成的。但我们其实并不需要知道它的组成,我们只需要知道这个字母有没有在这个单词里出现过就行。那我们可以用二进制数的方式来存一个字母是否在单词里出现,因为二进制只用0和1,那么我们可以设定一个26位长的二进制数,即一开始是26个0(000000000……00)哪个字母出现了就把对应的数从0变成1,比如a就是把第一个0变成1即可,然后我们把这个二进制数存入vector里即可(比起上面的vector里存map容器,这里存的只是一个int,方便很多)。到时候比较,我们只需要用到&即可,&的功能是比较两个二进制数,如果两边都为1才为1,比如两个二进制数0010和0110,除了第二位都为1以外,其余位置要么只有一个1,要么都为0,所以运算后的结果为0010(转换成bool就是true),如果一个1都没有就直接是0(转换成bool就是false),我们可以用这个方法来判断单词是否有相同的地方,比如单词abc和aef就是0111和00110001,运算后为0001,说明有相同的,如果是ab和cd,就是0011和1100,运算后为0,说明没有相同的,然后我们在计算然后取最大值即可。

class Solution {
public:
    int maxProduct(vector<string>& words) {
        vector<int>v;
        for(auto i:words)
        {
            int maxk=0;
            for(auto j:i)
            {
                maxk |= 1<< (j-'a');
            }
            v.push_back(maxk);
        }
        int n=v.size(),max_num=0;;
        for(int i=0;i<n;i++)
        {
            
            for(int j=i+1;j<n;j++)
            {
                int num=words[i].size()*words[j].size();
                if(!(v[i]&v[j]))
                    max_num=max(max_num,num);
                else continue;
            }
        }
        return max_num;
    }
};

AcWing——算法基础

40. 顺时针打印矩阵 - AcWing题库

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

样例
输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]

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

我们从x=0,y=0处开始逐步把数存入数组里,准备四个方向:上(-1,0),右(0,1),下(1,0),左(0,-1),每次遍历的时候按照方向xy坐标的不同加在我们遍历的xy处就可以达到顺时针遍历,每当遇到边界或是到了之前的位置(转了一圈)就转方向。

class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
        int n=matrix.size();
        vector<int>v;
        if(!n)return v;
        int m=matrix[0].size();
        vector<vector<bool>>st(n,vector<bool>(m,false));
        int dx[]={-1,0,1,0},dy[]={0,1,0,-1};
        int x=0,y=0,d=1;
        for(int i=0;i<n*m;i++)
        {
            v.push_back(matrix[x][y]);
            st[x][y]=true;
            int a=x+dx[d],b=y+dy[d];
            if(a>=n||a<0||b<0||b>=m||st[a][b])
            {
                d=(d+1)%4;
                a=x+dx[d],b=y+dy[d];
            }
            x=a,y=b;
        }
        return v;
    }
};
801. 二进制中1的个数 - AcWing题库

给定一个长度为 n 的数列,请你求出数列中每个数的二进制表示中 1 的个数。

输入格式

第一行包含整数 n。

第二行包含 n 个整数,表示整个数列。

输出格式

共一行,包含 n 个整数,其中的第 i 个数表示数列中的第 i 个数的二进制表示中 1 的个数。

数据范围

1≤n≤100000
0≤数列中元素的值≤10^9

输入样例:
5
1 2 3 4 5

这里我们用到的是位运算的知识点,采用的是右移运算符(>>),使用格式是a>>b;意思是把数字a的二进制数向右移动b位,比如7>>2,就是把5的二进制数向右移动2位,7二进制是0111,向右移动两位就变成了01,我们就是采用这个方式,让一个数的二进制数上各个位的数移动到右边第一位,然后和&1,&是按位与的意思,它的意思是两个数的二进制数对应位置上都为1才为1,比如5&7就是0101&0111,运算结果就是0101,我们把右移的数和1进行&运算,就是只看一个数的最右边位置上是不是1,如果是1就就计算有一个1,然后再右移,在计算,最后右移完后就可以知道这个数的二进制有几个1了。(我们这里从32开始右移,移到1停止,从32开始是因为int类型是32字节,即二进制有32位数)

#include<iostream>
using namespace std;
int main()
{
    int m,num,math;
    cin>>m;
    while(m--)
    {
        math=0;
        cin>>num;
        for(int i=32;i>0;i--)
            if(num>>i&1)math++;
        cout<<math<<" ";
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值