第二周算法题(链表,高精度,滑动窗口)

第二周(10.30-11.5)

第一题:

题目来源:https://www.acwing.com/problem/content/829/
题目描述:

实现一个双链表,双链表初始为空,支持 5种操作:

  1. 在最左侧插入一个数;
  2. 在最右侧插入一个数;
  3. 将第 k个插入的数删除;
  4. 在第 k 个插入的数左侧插入一个数;
  5. 在第 k个插入的数右侧插入一个数

现在要对该链表进行 M次操作,进行完所有操作后,从左到右输出整个链表。

注意:题目中第 k个插入的数并不是指当前链表的第 k个数。例如操作过程中一共插入了 n个数,则按照插入的时间顺序,这 n 个数依次为:第 1个插入的数,第 2个插入的数,…第 n个插入的数。

输入格式

第一行包含整数 M,表示操作次数。

接下来 M行,每行包含一个操作命令,操作命令可能为以下几种:

  1. L x,表示在链表的最左端插入数 x。
  2. R x,表示在链表的最右端插入数 x。
  3. D k,表示将第 k个插入的数删除。
  4. IL k x,表示在第 k个插入的数左侧插入一个数。
  5. IR k x,表示在第 k个插入的数右侧插入一个数。
输出格式

共一行,将整个链表从左到右输出。

数据范围

1≤M≤100000
所有操作保证合法。

输入样例:
10
R 7
D 1
L 3
IL 2 10
D 3
IL 2 7
L 8
R 9
IL 4 7
IR 2 2
输出样例:
8 7 7 3 2 9
解题思路:
10万数据太庞大,只能用数组模拟双链表来完成,不然频繁分配内存,时间太过复杂。
解题代码:
#include <stdio.h>
#include <string.h>
int l[100003];
int r[100003];
int data[100003];
int idx = 2;
void init() {//初始化
    r[0] = 1; // 左头节点
    l[1] = 0; // 右尾结点
}
void add_l(int x) { // 头插
    data[idx] = x;
    l[idx] = 0;
    r[idx] = r[0];
    l[r[0]] = idx;
    r[0] = idx;
    idx++;
}
void add_r(int x) { // 尾插
    data[idx] = x;
    r[idx] = 1;
    l[idx] = l[1];
    r[l[1]] = idx;
    l[1] = idx;
    idx++;
}
void insert_r(int pos, int x) { // 右插
pos++;
data[idx] = x;
l[idx] = pos;
r[idx] = r[pos];
l[r[pos]] = idx;
r[pos] = idx;
idx++;
}
void insert_l(int pos, int x) { // 左插
    pos++;
    pos = l[pos];
    data[idx] = x;
    l[idx] = pos;
    r[idx] = r[pos];
    l[r[pos]] = idx;
    r[pos] = idx;
    idx++;
}
void del(int k) { // 删除
    k++;
    r[l[k]] = r[k];
    l[r[k]] = l[k];
}
int main() {
    int m;
    scanf("%d", &m);
    getchar();
    init();
    while (m--) {
        char str[1000];
        gets(str);

    if (str[0] == 'L') {
        int x;
        sscanf(str, "%*s %d", &x);
        add_l(x);
    }
    else if (str[0] == 'R') {
        int x;
        sscanf(str, "%*s %d", &x);
        add_r(x);
    }
   else if (str[0] == 'D') {
        int x;
        sscanf(str, "%*s %d", &x);
        del(x);
    }
    else if (str[0] == 'I') {
        int x, pos;
        sscanf(str, "%*s %d %d", &pos, &x);
        if (str[1] == 'L') {
            insert_l(pos, x);
        }
        else if (str[1] == 'R') {
            insert_r(pos, x);
        }
    }
}

for (int i = r[0]; i != 1; i = r[i]) {
    printf("%d ", data[i]);
}
return 0;
}

第二题:

题目来源:https://www.acwing.com/problem/content/796/,https://www.acwing.com/problem/content/795/,https://www.acwing.com/problem/content/794/…
题目描述:本题是一个自组题,由5道题组成,分别包含了高精度加法,减法,乘法,除法求整,除法求余以及高精度的小数位数。
高精度加法代码:
#include <stdio.h>
#include <string.h> 
int main(){
	char str1[100001];
	char str2[100001];
	gets(str1);
	gets(str2);
	int a[100000]={0};
	int b[100000]={0};
	int c[100000]={0};
	int la,lb,lc;
	la=strlen(str1);
	lb=strlen(str2);
	 int i=0;
	 for(i=0;i<la;i++){
	 	a[la-i]=str1[i]-'0'; 
	 }
	for(i=0;i<lb;i++){
	   b[lb-i]=str2[i]-'0';	
	}
	int max=la;
	if(lb>max){
		max=lb;
	}
	for(i=1;i<=max;i++){
	c[i]+=a[i]+b[i];
		c[i+1]=c[i]/10;		
		c[i]%=10;
	}
	if(c[max+1]!=0){
		for(i=max+1;i>=1;i--){
			printf("%d",c[i]);
		}
	}
	else
	for(i=max;i>=1;i--){
		printf("%d",c[i]); 
	}
	return 0;
} 
高精度减法代码:
#include <stdio.h>
#include <string.h>
int i,j,m; 
int main() {
	char  str1[100001] = { 0 };
	char  str2[100001] = { 0 };
	gets(str1);
	gets(str2);
	if (strcmp(str1, str2) == 0) {
		printf("0");
		return 0;
	}
	int len1 = strlen(str1);
	int len2 = strlen(str2);
	int index = 0;
	if (len1 < len2) {
		index = 1;
	}
	else if (len1 == len2) {
		for ( i = 0; i < len1; i++) {
			int k = str1[i]-'0';
			int u = str2[i]-'0';
			if (k < u) {
				index = 1;
				break;
			}
			if(k>u){
				index=0;
				break;
			}
		}
	}
	else
	{
		index = 0;
	}
	int a[100001] = { 0 };
	int b[100001] = { 0 };
	int h = 0;
	for ( i = len1 - 1; i >= 0; i--) {
		int k = str1[i] - '0';
		a[h]=k;
		h++;
	}
	h = 0;
	for ( i = len2 - 1; i >= 0; i--) {
		int k = str2[i] - '0';
		b[h] = k;
		h++;
	}
	if (index == 1) {
		printf("-");
	}
	int ans[100005] = { 0 };
	if(index==0){
	for (i = 0; i < len1; i++) {
		int k = a[i] - b[i];
		ans[i] = k;
		if (k >= 0) {
			continue;
		}
		else
		{
			for ( j = i+1; j < len1; j++) {
				if (a[j] == 0) {
					continue;
				}
				else {
					a[j]--;
					for ( m = i + 1; m < j; m++) {
						a[m] = 9;
					}
					ans[i] += 10;
					break;
				}
			}
		}
	}
	int l = 1;
	for ( i = len1 - 1; i >= 0; i--) {
		if(ans[i]==0&&l==1){
			continue;
		}		
		else
	   {
		   	l=0;
			printf("%d", ans[i]);}
	}
	}
	if (index == 1) {
		for ( i = 0; i < len2; i++) {
			int k = b[i] - a[i];
			ans[i] = k;
			if (k >= 0) {
				continue;
			}
			else
			{
				for ( j = i + 1; j < len2; j++) {
					if (b[j] == 0) {
						continue;
					}
					else {
						 b[j]--;
						 for ( m = i + 1; m < j; m++) {
							 b[m] = 9;
						 }
						ans[i] += 10;
						break;
					}
				}
			}
		}
		int l = 1;
		for ( i = len2 - 1; i >= 0; i--) {
		if(ans[i]==0&&l==1){
			continue;
		}		
		else
	   {
		   	l=0;
			printf("%d", ans[i]);}
	}
	}
return 0;
}
高精度乘法代码:
#include <stdio.h>
#include <string.h>
int main() {
	int i,j;
    char str1[100007] = { 0 };
    char str2[100000] = { 0 };
    gets(str1);
    gets(str2);
    if(strcmp(str2,"0")==0){
    	printf("0");
    	return 0;
	}
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int a[100007] = { 0 };
    int b[100001] = { 0 };
    int k,h=0;
    for (i = len1 - 1; i >= 0; i--) {
        k = str1[i] - '0';
        a[h] = k;
        h++;
    }
    h = 0;
    for (i = len2 - 1; i >= 0; i--) {
        k = str2[i] - '0';
        b[h] = k;
        h++;
    }
    int ans[100009]={0};
    for (i = 0; i < len2; i++) {
        int g = i;
        for ( j = 0; j <= len1; j++) {
            int k = a[j] * b[i];
            ans[g] += k;
            if (ans[g] >= 10) {
                ans[g + 1] += ans[g] / 10;
                ans[g] %= 10;
            }
            g++;
        }
    }
     j = 1;
    for (i = 100009; i >= 0; i--) {
        if (ans[i] == 0 && j) {
            continue;
        }
        else {
            j = 0;
            printf("%d", ans[i]);
        }
    }
    return 0;
}
高精度除法取整与取余代码:
#include <stdio.h>
#include <string.h>
int main() {
	int b;
	char str[100002] = { 0 };
	gets(str);
	scanf("%d", &b);
	if(strcmp(str,"0")==0){
	    printf("0\n0");
	    return 0;
	}
	int c[100001] = { 0 };
	int len = strlen(str);
	int a[100001] = { 0 };
	int h = 0;
	for (int i = 0; i < len; i++) {
		int k = str[i] - '0';
		a[h++] = k;
	}
	int k = 0;
	h = 0;
	for (int i = 0; i < len; i++) {
		k += a[i];
		c[h++] = k / b;
		k = k % b*10;
	}
	int g=0;
	for(int i=0;i<len;i++){
	    if(c[i]!=0){
	        g=1;
	        break;
	    }
	}
	if(g){
	int l = 1;
	for (int i = 0; i < len; i++) {
		if (c[i] == 0 && l) {
			continue;
		}
		else
		{
			l = 0;
			printf("%d", c[i]);
		}
	}
	printf("\n%d", k/10);}
	else{
	    printf("0\n%s",str);
	}
	return 0;
}
除法小数高精度代码:
#include <stdio.h>
#include <string.h>
int main(){
	int a,b;
	scanf("%d %d",&a,&b);
	int c=a/b;
	char str[20000]={0};
	sprintf(str,"%d",c);
	strcat(str,".");
	int n;
	int d=a%b;
	scanf("%d",&n);
	int i;
	for(i=0;i<n;i++){
		int m=(d*10/b);
		char s[2];
		sprintf(s,"%d",m);
		strcat(str,s);
		d=d*10%b;
	}
	printf("%s",str);
return 0;

} 

第三题:

题目来源:209. 长度最小的子数组 - 力扣(LeetCode)
题目描述:一种算法,两种题型,分别求长度的最大和最小值。
类一:
给定一个含有 n 个正整数的数组和一个正整数 target
找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
解题思路:
本题主要运用了滑动窗口算法,如果当前的和小于目标值,则让右指针不断向右移,当大于等于时,进入左指针循环,左指针不断地向右指针靠拢,直到小于目标值,跳出循环,循环外循环,直到又指针碰到边界输出结果。需要注意的是,滑动窗口的遍历,一般用右指针来遍历,同时不断的更新长度,若小于既有的最小值,则更新最小值。
代码如下:
int minSubArrayLen(int target, int* nums, int numsSize) {
   int minlenth=0;
   int i=0;
   int sum=0;
   int l=0,r=0;
   int lenth=0;
   while(r<numsSize){
   	sum+=nums[r];
   	while(sum>=target){
   		lenth=r-l+1;
   		if(lenth<minlenth||minlenth==0){
   			minlenth=lenth;
		   }
		   sum-=nums[l];
		   l++;
	   } 	r++;
   }
   return minlenth;
       }
本题需要注意的是,在什么地方计算lenth长度,才能处理边界问题,选择在移动左标的循环中计算长度,既能计算每一次左标右移的结果,又可以处理边界问题,即如果加最后一个元素大于才会进入循环,否则可以不用计算。

类二:

题目描述:

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
解题思路:
用一个阿斯克码数组储存,字符串数组中每个元素出现的位置的下标,并且用了左右两个指针,利用滑动窗口的算法来计算之间的距离。
解题代码:
int lengthOfLongestSubstring(char* s) {
  int n = strlen(s);
  int i = 0, j = 0, max = 0;
  int index[256] = {0};
  while (j < n) {
    if (index[s[j]] > i) {
      i = index[s[j]];
    }
    index[s[j]] = j + 1;
    if (max < j - i + 1) {
      max = j - i + 1;
    }
    j++;
  }
  return max;
}
这段代码的目标是找到给定字符串s中最长的不含重复字符的子串的长度。它使用了滑动窗口和哈希表(在这里是index数组)的方法。以下是对代码的详细解读:
  1. int n = strlen(s);:获取字符串s的长度。
  2. int i = 0, j = 0, max = 0;:初始化两个指针ij,它们表示滑动窗口的左右边界。max用来存储最长的不含重复字符的子串的长度。
  3. int index[256] = {0};:初始化一个index数组,用来存储每个字符最后出现的位置。数组的大小是256,因为ASCII字符的范围是0-255。
  4. while (j < n) {...}:当右指针j小于字符串的长度n时,执行循环。
    • if (index[s[j]] > i) {...}:如果字符s[j]index数组中的值大于左指针i,说明字符s[j]在滑动窗口中已经出现过,此时需要更新左指针i的位置为index[s[j]],以排除重复字符。
    • index[s[j]] = j + 1;:更新字符s[j]index数组中的值为j+1。这里加1是为了区分字符未出现(对应的index值为0)和字符出现在字符串的开头(对应的index值为1)的情况。
    • if (max < j - i + 1) {...}:如果当前滑动窗口的长度j-i+1大于max,则更新max的值。
    • j++;:右指针j向右移动一位,扩大滑动窗口。
  5. return max;:返回最长的不含重复字符的子串的长度。
  • 27
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xiao Ling.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值