今天继续做数组,打算今后,每天五道题的进度,目前是每天2道简单+3道中等。
打算今天把数组主要的思路搞完,就开始下一个分类。
之后就是边学习新的,边练习旧的。
1、搜索插入位置(难度:简单)
AC代码
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int low=0,high=nums.size()-1;
int mid = low+(high-low)/2;
while(low<=high){
if(nums[mid]>target){
high=mid-1;
mid = low+(high-low)/2;
}
else if(nums[mid]<target){
low=mid+1;
mid = low+(high-low)/2;
}
else{
return mid;
}
}
return low+(high-low)/2;
}
};
看到这个时间复杂度,就想起来二分法,思路比较简单,记得学数据机构的时候学过,需要注意的就是这个写法mid = low+(high-low)/2;
最好用这个,因为mid = (high+low)/2;
如果数据太大的话加法容易溢出。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int length = nums.size();
int low=0,high=length-1;
int left,right;
int mid = low+(high-low)/2;
if(length==0){
return {-1,-1};
}
while(low<=high){
if(nums[mid]>target){
high=mid-1;
mid = low+(high-low)/2;
}
else if(nums[mid]<target){
low=mid+1;
mid = low+(high-low)/2;
}
//nums[mid]=target
else{
left = mid;
right = mid;
if(left!=0){
while(left!=0 && nums[left]==nums[left-1]){
left--;
}
}
if(right!=length-1){
while(right!=length-1 && nums[right]==nums[right+1]){
right++;
}
}
return {left,right};
}
}
return {-1,-1};
}
};
2、在排序数组中查找元素的第一个和最后一个位置(难度:中等)
AC代码
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int length = nums.size();
int low=0,high=length-1;
int left,right;
int mid = low+(high-low)/2;
if(length==0){
return {-1,-1};
}
while(low<=high){
if(nums[mid]>target){
high=mid-1;
mid = low+(high-low)/2;
}
else if(nums[mid]<target){
low=mid+1;
mid = low+(high-low)/2;
}
//nums[mid]=target
else{
left = mid;
right = mid;
if(left!=0){
while(left!=0 && nums[left]==nums[left-1]){
left--;
}
}
if(right!=length-1){
while(right!=length-1 && nums[right]==nums[right+1]){
right++;
}
}
return {left,right};
}
}
return {-1,-1};
}
};
没看题解怎么做的,就还是用的二分法,就在找到和target相等元素之后,又使用了left和right这一对新指针,left往左,right往右,和之前的三数之和里找重复元素的思路一样(双指针的思路算是应用的淋漓尽致的了)(够够的) ,注意一下两边边界问题就OK了。(虽然说是中等题,但感觉和简单的难度也差不多)
3、蜡烛之间的盘子(难度:中等)
超时了
class Solution {
public:
vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
int low,high,count;
int length=queries.size();
int i,j,k;
vector <int> ans;
for(i=0;i<length;i++){
count=0;
low=queries[i][0];
high=queries[i][1];
while(s[low]!='|'){
low++;
}
while(s[high]!='|'){
high--;
}
if(low>=high){
ans.push_back(0);
continue;
}
for(j=low;j<=high;j++){
if(s[j]=='*'){
count++;
}
}
ans.push_back(count);
}
return ans;
}
};
AC代码
原本以为自己之前的代码时间复杂度也可以,不过还是超时了,用的还是双指针的思想,不过,确实我有些思维固化了,只想着先获取边界,接着在每次用双指针从两边分别获取,缩小区间范围。这样相当于每次循环里都要再嵌套一个循环,如果情况比较坏,需要遍历整个字符串,时间复杂度就上去了。
看了下官方的题解,看到说有个预处理,当时只看了对*
号做前缀和,觉得自己会了,后面就没再看。等到自己写的时候,还是乱七八糟小毛病一堆以及左右指针不知道该怎么改,不过最后终于是能够模仿着预处理的思路,想起来左右指针怎么来处理。(还是挺有成就感的)
class Solution {
public:
vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
int low,high,count,count1,count2;
int length=queries.size();
int n = s.size();
int i,j1,j2,k;
vector <int> ans;
vector <int> sum_star(n,0);
vector <int> left(n,0);
vector <int> right(n,0);
count=0;
count1=0;
count2=n-1;
//对某个下标之前的星号个数做统计(*的前缀和)
for(k=0;k<n;k++){
if(s[k]=='*'){
count++;
}
sum_star[k]=count;
}
//指针从左往右,确定右边界
for(j1=0;j1<n;j1++){
if(s[j1]=='|'){
count1=j1;
}
left[j1]=count1;
}
//指针从右往左,确定左边界
for(j2=n-1;j2>=0;j2--){
if(s[j2]=='|'){
count2=j2;
}
right[j2]=count2;
}
for(i=0;i<length;i++){
count=0;
low=queries[i][0];
high=queries[i][1];
ans1=sum_star[high]-sum_star[low];
ans2=high-low;
//区间里只有一个蜡烛或没有蜡烛
if(left[high]<=right[low]){
ans.push_back(0);
continue;
}
ans.push_back(sum_star[left[high]]-sum_star[right[low]]);
}
return ans;
}
};
4、找出数组中的第一个回文字符串(难度:简单)
AC代码
思路比较简单,不多说了,上代码
class Solution {
public:
string firstPalindrome(vector<string>& words) {
int i,left,right;
int n=words.size();
string str;
string ans="";
for(i=0;i<n;i++){
left=0;
right=words[i].length()-1;
while(left<right && words[i][left]==words[i][right]){
left++;
right--;
}
if(words[i][left]!=words[i][right]){
continue;
}
//奇数个和偶数个
if(left==right || left==right+1){
return words[i];
}
}
return ans;
}
};
5、构建回文串检测(难度:中等)
解答错误
class Solution {
public:
vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
vector <bool> ans;
int i,left,right,k,count;
int n=queries.size();
string str;
for(i=0;i<n;i++){
left=queries[i][0];
right=queries[i][1];
k=queries[i][2];
count=0;
while(left<right && s[left]==s[right]){
left++;
right--;
}
//原本不是回文
//看通过替换能否变成回文
if(s[left]!=s[right]){
if(k==0){
ans.push_back(false);
}
else{
while(left<right){
if(s[left]!=s[right]){
count++;
}
left++;
right--;
}
if(count>k){
ans.push_back(false);
}
else{
ans.push_back(true);
}
}
continue;
}
//奇数个和偶数个
if(left==right || left==right+1){
ans.push_back(true);
}
}
return ans;
}
};
当我看到这个错误案例的时候,我的小脑萎缩了一下。自信满满的 我打开评论区,看是不是样例给错了,结果。。
这题居然还可以重新排列,人家还特地加粗了,愣是没看着。。
我心想,这不完蛋,思路都得重来
确实作为中等题,不该这么简单的
以后要仔细审题啊友友们
看到题解说的方法,标题是,前缀和+位运算,想想也是哈,毕竟可以重新排列,都不在乎顺序了,前缀和是我目前学到的最好的方法了。
于是,我就没看题解代码,想自己敲一下,看能不能AC。
## AC代码
又超时了
前缀异或的方法没想起来怎么写,还是用的自己的笨方法,又超时了,哎呀,扶额,这俩测试样例,我真的。。。
class Solution {
public:
vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
vector <bool> ans;
// vector <int> alphabet={a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z};
//小写英文字母ascii码为97-122
vector <int> alphabet(123,0);
int i,left,right,j,k,k1,count;
int n=queries.size();
string str;
for(i=0;i<n;i++){
alphabet.assign(123, 0);
left=queries[i][0];
right=queries[i][1];
k1=queries[i][2];
count=0;
for(k=left;k<=right;k++){
alphabet[s[k]]++;
}
for(j=97;j<=122;j++){
if(alphabet[j]%2!=0){
//区间内单个字母的个数
count++;
}
}
//区间内字母个数是偶数个
if((right-left+1)%2==0){
if(k1>=ceil(count/2)){
ans.push_back(true);
}
else{
ans.push_back(false);
}
}
//区间内字母个数是奇数个
if((right-left+1)%2!=0){
if(k1>=ceil((count-1)/2)){
ans.push_back(true);
}
else{
ans.push_back(false);
}
}
}
return ans;
}
};
AC代码
依旧是没看题解的方法,用的自己的笨方法,这已经算是暴力枚举了吧。。
主要思路就是,针对题目里说的字符串里都是小写英文字母,那么就仿照3、蜡烛之间的盘子
这道题的做法,同样是给定区间,同样是计算每个字母的前缀和,不过相比第3题的一维数组,我这里就得用二维,并且字母在前字符串下标在后[字母][下标]
,反过来我试了,发现到后面的时候时间复杂度降不下来。用这个二维数组记录每个字符出现的次数。后面不说了,和蜡烛那个题思路差不多。
总结下来就是这些不考虑顺序的数组还是挺适合用前缀和的。
class Solution {
public:
vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
vector <bool> ans;
//{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z};
//小写英文字母ascii码为97-122
// vector <vector<int>> alphabet(s.size(),123,0);
int n1=s.size();
vector<vector<int>> alphabet(123, vector<int>(n1, 0));
int i,i1,left,right,j,k,k1,count;
int n=queries.size();
string str;
for(i1=0;i1<n1;i1++){
if(i1>0){
alphabet['a'][i1]=alphabet['a'][i1-1];
alphabet['b'][i1]=alphabet['b'][i1-1];
alphabet['c'][i1]=alphabet['c'][i1-1];
alphabet['d'][i1]=alphabet['d'][i1-1];
alphabet['e'][i1]=alphabet['e'][i1-1];
alphabet['f'][i1]=alphabet['f'][i1-1];
alphabet['g'][i1]=alphabet['g'][i1-1];
alphabet['h'][i1]=alphabet['h'][i1-1];
alphabet['i'][i1]=alphabet['i'][i1-1];
alphabet['j'][i1]=alphabet['j'][i1-1];
alphabet['k'][i1]=alphabet['k'][i1-1];
alphabet['l'][i1]=alphabet['l'][i1-1];
alphabet['m'][i1]=alphabet['m'][i1-1];
alphabet['n'][i1]=alphabet['n'][i1-1];
alphabet['o'][i1]=alphabet['o'][i1-1];
alphabet['p'][i1]=alphabet['p'][i1-1];
alphabet['q'][i1]=alphabet['q'][i1-1];
alphabet['r'][i1]=alphabet['r'][i1-1];
alphabet['s'][i1]=alphabet['s'][i1-1];
alphabet['t'][i1]=alphabet['t'][i1-1];
alphabet['u'][i1]=alphabet['u'][i1-1];
alphabet['v'][i1]=alphabet['v'][i1-1];
alphabet['w'][i1]=alphabet['w'][i1-1];
alphabet['x'][i1]=alphabet['x'][i1-1];
alphabet['y'][i1]=alphabet['y'][i1-1];
alphabet['z'][i1]=alphabet['z'][i1-1];
}
alphabet[s[i1]][i1]++;
}
for(i=0;i<n;i++){
left=queries[i][0];
right=queries[i][1];
k1=queries[i][2];
count=0;
for(k=97;k<=122;k++){
if(left!=0){
if((alphabet[k][right]-alphabet[k][left-1])%2!=0){
count++;
}
}
else{
if((alphabet[k][right]-0)%2!=0){
count++;
}
}
}
//区间内字母个数是偶数个
if((right-left+1)%2==0){
if(k1>=ceil(count/2)){
ans.push_back(true);
}
else{
ans.push_back(false);
}
}
//区间内字母个数是奇数个
if((right-left+1)%2!=0){
if(k1>=ceil((count-1)/2)){
ans.push_back(true);
}
else{
ans.push_back(false);
}
}
}
return ans;
}
};
下一篇博客再来学习题解的方法!一天5道完成了!