第二周(10.30-11.5)
第一题:
题目来源:https://www.acwing.com/problem/content/829/
题目描述:
实现一个双链表,双链表初始为空,支持 5种操作:
- 在最左侧插入一个数;
- 在最右侧插入一个数;
- 将第 k个插入的数删除;
- 在第 k 个插入的数左侧插入一个数;
- 在第 k个插入的数右侧插入一个数
现在要对该链表进行 M次操作,进行完所有操作后,从左到右输出整个链表。
注意:题目中第 k个插入的数并不是指当前链表的第 k个数。例如操作过程中一共插入了 n个数,则按照插入的时间顺序,这 n 个数依次为:第 1个插入的数,第 2个插入的数,…第 n个插入的数。
输入格式
第一行包含整数 M,表示操作次数。
接下来 M行,每行包含一个操作命令,操作命令可能为以下几种:
L x
,表示在链表的最左端插入数 x。R x
,表示在链表的最右端插入数 x。D k
,表示将第 k个插入的数删除。IL k x
,表示在第 k个插入的数左侧插入一个数。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;
}