PS:算法并非原创,仅作个人学习记录使用,侵删
题目描述
算法分析
个人的算法思路是:遍历一遍数组,每次根据是否连续进行数组分割和结果记录。
后来在看了各类算法博客之后,大致上都是这种思路,但是可以采用“双指针”方法使得算法更加清晰。
代码实现
【C】
/*
该算法实现使用了双指针方法,分别指向连续区间的起始位置和终止位置
*/
char** summaryRanges(int* nums, int numsSize, int* returnSize) {
//nums:待处理数组,numsSize:待处理数组长度,returnSize:返回的数组长度
char** ret = (char**)malloc(sizeof(char*) * numsSize);//返回的字符数组,动态分配内存
//变量初始化
*returnSize = 0;
int i = 0;
int low = 0;//低指针
int high = 0;//高指针
//数组遍历
while (i < numsSize) {
low = i;//记录连续区间的起始位置
i++;
//如果一直连续,则遍历指针一直移动
while (i < numsSize && nums[i] == nums[i - 1] + 1) {
i++;
}
//连续区间结束,更新结束位置的指针
high = i - 1;
//构造已有的连续空间结果
char* temp = (char*)malloc(sizeof(char) * 25);//临时字符数组
sprintf(temp, "%d", nums[low]);//将nums[low](起始位置的值)输出到指定字符串中
/*
int sprintf(char *buffer,const char *format,[argument]…);
sprintf函数的功能与printf函数的功能基本一样,只是它把结果输出到指定的字符串中
buffer:char型指针,指向将要写入的字符串的缓冲区。
format:格式化字符串。
[argument]...:可选参数,可以是任何类型的数据。
*/
if (low < high) {//如果连续区间的长度大于一
sprintf(temp + strlen(temp), "->");//加上“->”
sprintf(temp + strlen(temp), "%d", nums[high]);//加上终止位置的值
}
ret[(*returnSize)++] = temp;//ret数组中加入temp结果,returnSize++
}
return ret;//返回字符数组结果
}
C语言参考网址
【C++】
/*
C++解法中,同样用到了双指针的思想,只是终止位置的指针用遍历指针替代,导致最后一个连续区间的处理情况有些复杂
*/
class Solution {
public:
vector<string> summaryRanges(vector<int>& nums){
vector<string> res;//res格式为vector,方便添加元素
int n=nums.size();//待处理数组长度
//处理元素的数据类型,转化为long long型
for(int i=0;i<n;i++){
nums[i]=(long long)nums[i];
}
//特殊情况:数组长度为0,不需要做处理
if(0==n){
return res;
}
string tmp=to_string(nums[0]);//tmp用于存储当前遍历到的连续区间的临时结果,当前字符串存入起始位置的元素值
int start=0;//开始位置
//遍历数组
for(int i=1;i<n;i++){
//如果区间不连续,需要进行处理
if(nums[i]!=nums[i-1]+1){
if(i==start+1){//不连续区间长度为1时
res.push_back(tmp);//结果中添加单个元素值
//vector.push_back(),在vector结构中添加元素
start=i;//更新起始位置,继续后续遍历
tmp=to_string(nums[i]);//tmp起点变换
}
else{//不连续区间长度大于1时,
tmp+="->";
tmp+=to_string(nums[i-1]);
//tmp构造成功
res.push_back(tmp);//添加进结果
start=i;//更新起始位置
tmp=to_string(nums[i]);//tmp起点变换
}
}
//如果一直连续,i++
}
//遍历完成之后,i=n-1,为了弥补双指针中终止位置的缺失,需要考虑最后一个区间
if(start==n-1){//如果xx~n-2是一个连续数组,之后start=n-1,说明最后一个连续区间长度等于1
res.push_back(tmp);//结果中只添加单个元素值
}
else{//如果最后一个连续区间起始位置不是n-1,说明连续区间长度大于1
tmp+="->";
tmp+=to_string(nums[n-1]);
res.push_back(tmp);
}
return res;//返回结果
}
};
C++参考网址
【java】
/*
java采用的是直接遍历的思路,但是没有使用典型的双指针方法。
它在每个区间开始,给出临时结果,写入起始位置,之后不断向前遍历,如果最终停下来的位置和开始遍历的位置不同,进行临时结果构造,否则直接写入。由此进行一次遍历得出所有结果
*/
class Solution {
public List<String> summaryRanges(int[] nums) {
List<String> list = new ArrayList<>();//结果列表,初始为空
int pos = 0;//用于遍历
while (pos < nums.length) {//进行数组遍历
StringBuilder it = new StringBuilder(""+nums[pos]);//it存储当前区间的结果,初始时存入起始位置元素值
int temp = pos;//起始位置
while (pos + 1 < nums.length && nums[pos + 1] == nums[pos] + 1)//一直连续
pos++;//一直向前遍历
if (pos != temp)//如果起始位置和遍历位置不相同,说明连续区间长度大于1
it.append("->").append(nums[pos]);//it临时结果中添加"->终止位置元素值"
list.add(it.toString());//在结果列表中加入
pos++;//继续遍历
}
return list;
}
}
Java参考网址
【python】
#
#python的解题思想和C++类似。
#不同的是,它不使用遍历指针作为终止位置指针,而是用一个连续区间长度变量和起始指针相结合得出终止位置指针。
#由于终止位置指针的缺失,同样需要对最后一个连续区间进行另外的处理
#
class Solution:
def summaryRanges(self, nums):
"""
:type nums: List[int]
:rtype: List[str]
"""
n=len(nums)
res=[]#结果列表,初始为空
count=0#连续区间长度
#特殊情况,数组长度为0,不需要处理
if n==0:
return res
#数组长度为1,结果列表只有一个
elif n==1:
temp=str(nums[0])
res.append(temp)#append()添加列表元素
return res
#数组长度大于1
else:
aa=nums[0]#连续区间起始位置
temp=str(nums[0])#temp存储当前区间结果
for i in range(1,n):#遍历数组
if nums[i]-nums[i-1]==1:#如果依然是连续区间
count += 1#连续区间长度+1
else:#出现不连续区间
if count==0:#连续区间长度为1
res.append(temp)
aa=nums[i]#更细起始位置
temp=str(nums[i])
else:#连续区间长度大于1
#构造连续区间对应的结果
temp+="->"
temp+=str(aa+count)#此处说明了count的作用
res.append(temp)#将连续区间结果添加进结果列表
aa=nums[i]#更新起始位置
count=0#更新连续区间长度
temp=str(nums[i])#temp结果更新
if count==0:#最后一个连续区间,如果长度为1
res.append(temp)
else:#最后一个连续区间,长度大于1
temp+="->"
temp+=str(aa+count)
res.append(temp)
return res;