2022-01-03每日刷题打卡

2022-01-03每日刷题打卡

飞书——每日一题

6. Z 字形变换

难度中等1427收藏分享切换为英文接收动态反馈

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N
A P L S I I G
Y   I   R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

示例 1:

输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"

模拟,开一个二维数组v,准备一个控制方向的变量ans=1,从位置第一行开始,放一个字符后,位置行数+ans,即如果ans是1,那么就是往下走一行,如果ans是-1,就往上走一行,每次ans走到底(位置行数+ans==numRows)或走到头(位置行数+ans<0)时调转方向(改变ans正负性),最后拿一个字符串一行行遍历二维数组v,把遍历到的字符都加在自己身上即可。(顺带一题,当numrows为1时,我们直接返回s就行)

class Solution {
public:
    string convert(string s, int numRows) {
        if(numRows==1)return s;
        vector<string>v(numRows);
        int ans=1,l=0;
        for(auto i:s)
        {
            v[l].push_back(i);
            if(l+ans>=numRows)ans=-1;
            else if(l+ans<0)ans=1;
            l+=ans;
        }
        string str;
        for(auto i:v)
        {
            for(auto j:i)
                str+=j;
        }
        return str;
    }
};
1185. 一周中的第几天

给你一个日期,请你设计一个算法来判断它是对应一周中的哪一天。

输入为三个整数:day、month 和 year,分别表示日、月、年。

您返回的结果必须是这几个值中的一个 {“Sunday”, “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”}。

示例 1:

输入:day = 31, month = 8, year = 2019
输出:“Saturday”

这题要是不查日历绝逼做不出来啊,直接进行一个模拟,准备一个字符串数组,根据下标存储星期(我这里写的和题目给的一样),查日历知道了1971年的第1天是周五,准备一个数ans计算天数,因为1971年第一天是周五,所以我们初始给ans设为4(为什么不是5,因为我们后面算星期的时候是要加上当天这一天的,如果ans设为5,再加上当天就是周六了,所以我们从1970年最后一天也就是周四开始算起,当然,如果你设置字符串数组不是从周日开时而是周一开始,那你的ans就是3),先for遍历年份,当年是闰年时ans+=366,非闰年时加上365(小知识,不是被4整除就是闰年,如果年份能被4整除但又能被100整除,那它就不是闰年,但被400整除是闰年,这个是小知识,感兴趣可以上网搜)然后遍历月份,从第一月开始到month的上一月,每次加上对应年份的日数,注意,遍历到二月时,如果当前年是闰年,那么二月是29天。当天数也遍历完后,ans再加上day,这样从1971年第一天到数据所给的天数就全部算完了,我们对ans%7,得到的结果是字符串数组的下标,取出对应的星期,返回即可。

class Solution {
public:
    string dayOfTheWeek(int day, int month, int year) {
        string week[]={"Sunday","Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
        int num[]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        int ans=4;
        for(int i=1971;i<year;i++)
        {
            ans+=((i % 4 == 0 && i % 100 != 0) || i % 400 == 0)?366:365;
        }
        for(int i=1;i<month;i++)
        {
            ans+=num[i-1];
            if (i == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)) ans++;
        }
        ans+=day;
        return week[ans%7];
    }
};

AcWing——每日一题

2041. 干草堆 - AcWing题库

贝茜对她最近在农场周围造成的一切恶作剧感到抱歉,她同意帮助农夫约翰把一批新到的干草捆堆起来。

开始时,共有 N 个空干草堆,编号 1∼N。

约翰给贝茜下达了 K个指令,每条指令的格式为 A B,这意味着贝茜要在 A…B 范围内的每个干草堆的顶部添加一个新的干草捆。

例如,如果贝茜收到指令 10 13,则她应在干草堆 10,11,12,13 中各添加一个干草捆。

在贝茜完成了所有指令后,约翰想知道 N 个干草堆的中值高度——也就是说,如果干草堆按照高度从小到大排列,位于中间的干草堆的高度。

方便起见,N 一定是奇数,所以中间堆是唯一的。

请帮助贝茜确定约翰问题的答案。

输入格式

第一行包含 N 和 K。

接下来 K 行,每行包含两个整数 A,B,用来描述一个指令。

输出格式

输出完成所有指令后,N 个干草堆的中值高度。

数据范围

1≤N≤10^6
1≤K≤25000
1≤A≤B≤N

输入样例:
7 4
5 5
2 4
4 6
3 5
输出样例:
1
样例解释

贝茜完成所有指令后,各堆高度为 0,1,2,3,3,1,00,1,2,3,3,1,0。

将各高度从小到大排序后,得到 0,0,1,1,2,3,30,0,1,1,2,3,3,位于中间的是 11。

这里用的主要是基础课里的差分,这里把题看明白后就知道,题目是给你一个N的数组,每次下命令,把a到b区间的所有元素+1,最后把数组排序,返回中间元素,题目完成。
如果我们一次次遍历ab区间把所有数都+1肯定是要超时的(不超时说明数据还不够狠),所以我们采用第797题一样的解法,准备两个数组,一个是差分数组,一个是差分数组的前缀和数组,每次ab区间要+1时,我们只用把差分数组中的a位置元素+1,再把b+1位置元素-1即可(不懂原理的建议去797. 差分 - AcWing题库看一看)最后遍历差分数组,计算各个前缀和,次=此前缀和即为所有草堆的高度大小,在对其进行排序,返回中间元素即可。

#include<iostream>
using namespace std;

const int N=1000010;
int h[N],q[N],a,b,k,n;

void quick_sort(int q[],int l,int r)
{
    if(l>=r)return;
    int x=q[(l+r)/2],i=l-1,j=r+1;
    while(i<j)
    {
        do i++;while(q[i]<x);
        do j--;while(q[j]>x);
        if(i<j)swap(q[i],q[j]);
    }
    quick_sort(q,l,j);
    quick_sort(q,j+1,r);
}

int main()
{
    cin>>n>>k;
    while(k--)
    {
        cin>>a>>b;
        h[a-1]++;
        h[b]--;
    }
    q[0]=h[0];
    for(int i=1;i<n;i++)
        q[i]=h[i]+q[i-1];
    quick_sort(q,0,n-1);
    cout<<q[n/2];
    return 0;
}
33. 搜索旋转排序数组

整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

示例 1:

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

题目说了nums有序,说到有序就该想到二分查找,但这题的有序有点特殊,nums数组排序后又旋转过了,所以是部分有序,但这种情况下我们依然可以用二分查找。首先一点,虽然nums旋转过后不是完全有序的,但你选一个数为界,这个数的左边或右边一定是有一边是有序的,比如4 5 6 7 8 1 2 3,你取7为界,那左边就是有序的,取2为界,那右边就是有序的。我们可以根据这一点进行二分查找,每次取数组的中间点,判断哪一边是有序的,再判断哪一边包含着target(如果有序那一边的数值区间没有target,就说明是无序那一边的),如果有序那一边有可能有target,就可以正常的二分查找了,如果无序那一边可能有target,就重复之前的操作。以此往复,要是最后找到的不是target,就返回-1,如果是就直接返回下标。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n=nums.size();
        if(!n)return -1;
        else if(n==1)return nums[0]==target?0:-1;
        int l=0,r=n-1;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(nums[mid]==target)return mid;
            if(nums[0]<=nums[mid])
            {
                if(nums[0]<=target&&nums[mid]>=target)r=mid-1;
                else l=mid+1;
            }
            else
            {
                if(nums[mid]<=target&&nums[n-1]>=target)l=mid+1;
                else r=mid-1;
            }
        }
        return -1;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值