OJ题
1旋转数组
要求:
1.1暴力写法
void rotate(int* nums, int numsSize, int k){
int kk = k;
while (kk--)//重复进行
{
//旋转一个数字
int tmp = nums[numsSize - 1];
for (int i = numsSize - 2; i >= 0; i--)
{
nums[i + 1] = nums[i]; //依次向后赋值覆盖,完成后,把最后一位原来的值赋给第一位
}
nums[0] = tmp; //一次循环完成一个数字的旋转
}
//这种写法过不了,耗时太久
1.2倒置写法
思路:
void InversionArray(int* nums, int n)
{
if (n < 2)
return;
int tmp = 0;
for (int i = 0; i < n / 2; i++)
{
tmp = nums[i];
nums[i] = nums[n - 1 - i];
nums[n - 1 - i] = tmp;
}
}
void rotate(int* nums, int numsSize, int k){
while (k > numsSize)
{
k = k - numsSize;
}
InversionArray(nums, numsSize - k);
int *p = &nums[numsSize - k];
InversionArray(p,k);
InversionArray(nums, numsSize);
}
2移除元素
int removeElement(int* nums, int numsSize, int val){
int i = 0;
while (i<numsSize)
{
if (nums[i] == val)
{
nums[i] = nums[numsSize - 1]; //用最后一个数字覆盖他
numsSize--; //最后一个数字被保存在当前位置,当前位置之前的数字被覆盖,所以,--
if (nums[i] == val) //如果这个换过来的最后一个数字还是val,再用当前末尾的覆盖,所以什么都不做,也不i++,让此位置进入下一轮循环被检验一次,让他再被替换一次
;
else
i++; //如果覆盖后并不是val,说明覆盖成功,找下一个是val的位置
}
else
i++; //当前就不是val所以走下一个
}
return numsSize;
}
3 搜索插入位置
int searchInsert(int* nums, int numsSize, int target)
{
int i = 0;
while (i<numsSize)
{
if (nums[i] == target)
return i;
else if (nums[i]>target&&(i==0||nums[i - 1] < target))
break;
else
i++;
}
return i;
}
4 赎金信
int CalArray(char* nums)
{
int i = 0;
while (nums[i] != 0)
{
i++;
}
return i;
}
bool canConstruct(char * ransomNote, char * magazine){
//暴力,每个字母只能用一次
int objSize = CalArray(ransomNote);
int souSize = CalArray(magazine);
int flag = souSize;
for (int i = 0; i < objSize;i++)
{
flag = souSize;
for(int j = 0;j < souSize;j++)
{
if (ransomNote[i] == magazine[j])
{
//相等,找下一个
magazine[j] = magazine[souSize - 1]; //因为不能重复用,所以对比完就替换掉
souSize--;
break;
}
}
if (flag == souSize)//说明obj[i]这个位置上没找到
{
return false;
}
}
return true;
}
5 回文
//判断位数
int judge(int x)
{
int i = 1;
while (x / 10 != 0)
{
i++;
x = x / 10;
}
return i;
}
bool isPalindrome(int x){
if (x < 0)
{
return false;
}
int front = 1;
int behind=x;
int pre = x;
int flag = judge(x); //5位
int divisor = 1;
int i = flag/2;
while (--flag)
{
divisor = divisor * 10;
}
while (i--)
{
front = (x / divisor)%10; //取第一个数字
divisor=divisor/10;
behind = pre % 10;
pre = pre / 10;
if (front == behind)
{
;
}
else
return false;
}
return true;
}
6 最后一个单词的长度
int lengthOfLastWord(char * s){
//如果没有单词返回0
//特殊情况,最后一个单词末尾有空格
int i = 0, j = 0; //给两个指针位置
int flag = 0;
while (s[j] != 0&&s[i]!= 0)
{
while ((s[j] >= 65 && s[j]<=90) || (s[j]>=97 && s[j] <= 122))
{
j++;//j位置为字母加加到下一位
}
if (s[j] == ' ')
{
flag = j;
while (s[flag] == ' ')
{
flag++;
}
if (s[flag] == 0)
{
return j - i;
}
else if ((s[flag] >= 65 && s[flag] <= 90) || (s[flag] >= 97 && s[flag] <= 122))
{
j = flag;
i = j;
}
}
}
return j - i;
}
7合并两个有序数组
思路:
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
if (m == 0)
{
for (int y = 0; y < n; y++)
{
nums1[y] = nums2[y];
}
}
if (n == 0)
return;
int i = m - 1;
int j = n - 1;
int cur = nums1Size - 1;
while (cur>=0&&(i>=0||j>=0))
{
if (i >= 0&&(j<0||nums1[i] > nums2[j]))
{
nums1[cur] = nums1[i];
cur--;
i--;
}
else if (j >= 0 && (i<0||nums1[i] <= nums2[j]))
{
nums1[cur] = nums2[j];
cur--;
j--;
}
}
}
8 长按键入
bool isLongPressedName(char * name, char * typed){
int i = 0;
int j = 0;
while (name[i] == typed[j]&&name[i]!=0)
{
i++;
j++;
if (name[i] == name[i-1])
;
else
{
while (typed[j] == typed[j - 1])
{
j++;
}
}
}
if (name[i] == 0 && typed[j] == 0)
{
return true;
}
return false;
}
9有序数组的平方
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* sortedSquares(int* A, int ASize, int* returnSize){
int* array = (int*)malloc(sizeof(A[0])*ASize);
int i = 0;
int j = 0;
int cur = 0;
while (i<ASize&&A[i] < 0)
{
i++;
}
j = i;
i = i - 1;
while(cur<ASize)
{
if (i >= 0&&(j>=ASize||abs(A[i]) < abs(A[j])))
{
array[cur] = A[i]*A[i];
i--;
cur++;
}
else if (j < ASize&&(i<0||abs( A[i])>= abs(A[j])))
{
array[cur] = A[j]*A[j];
j++;
cur++;
}
}
*returnSize = ASize;
return array;
}
注意:
开始时没有加这三个条件,被判断内存访问。调的人都崩溃了
报错AddressSanitizer: heap-buffer-overflow on address 0x60300000000c at pc 0x000000401c74 bp 0x7ffec50708c0 sp 0x7ffec50708b0
10 按奇偶排序树组
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* sortArrayByParity(int* A, int ASize, int* returnSize){
int* array = (int*)malloc(sizeof(int)*ASize);
int i = 0;
int j = ASize - 1;
int tmp = 0;
while (i < j){
if (A[i] % 2){ //i在前面,是奇数,待交换
if (!(A[j] % 2)) //j在后面,是偶数,待交换
{
tmp = A[i];
A[i] = A[j];
A[j] = tmp;
i++;
j--;
}
else{ //j位置就是奇数,不需要换
j--;
}
}
else //i为偶数,不需要换
{
i++;
}
}
tmp = ASize;
while(tmp>=0){
array[tmp] = A[tmp];
--tmp;
}
*returnSzie = ASize;
return array;
}
如上代码编译器上完全没问题,OJ上编译不通过,甚至报错,至今不能理解AddressSanitizer: stack-buffer-overflow on address 0x7ffc4bd52af4 at pc 0x000000404fe8 bp 0x7ffc4bd52930 sp 0x7ffc4bd52920
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* sortArrayByParity(int* A, int ASize, int* returnSize){
int* array = (int*)malloc(sizeof(int)*ASize);
int cur = 0;
int head = 0;
int tail = ASize - 1;
*returnSize = ASize; //没加这句报了同前面的错
while (cur >= 0 && cur < ASize){
if (A[cur] % 2)
{
array[tail--] = A[cur++];
}
else
{
array[head++] = A[cur++];
}
}
return array;
}
11 仅仅反转字母
int CalArray(char* nums)
{
int i = 0;
while (nums[i] != 0)
{
i++;
}
return i;
}
char * reverseOnlyLetters(char * S){
int head = 0;
int tail = CalArray(S)-1;
int tmp = 0;
while (head<tail)
{
if (S[head] >= 65 && S[head] <= 90 || S[head] >= 97 && S[head] <= 122) //头是字母
{
if (S[tail] >= 65 && S[tail] <= 90 || S[tail] >= 97 && S[tail] <= 122) //头尾都是字母,兴奋的交换
{
tmp = S[tail];
S[tail] = S[head];
S[head] = tmp;
head++;
tail--;
}
else//头是字母,尾不是
{
tail--;
}
}
else if (S[tail] >= 65 && S[tail] <= 90 || S[tail] >= 97 && S[tail] <= 122) //头不是字母,跳过,尾是
{
head++;
}
else //头尾都不是字母
{
head++;
tail--;
}
}
return S;
}
12 返回第三大的数字
int thirdMax(int* nums, int numsSize){
int first = 0; //存放最大的数
int second = 0; //存放第二大的数
int third = 0; //存放第三大的数
int flag1 = 0; //0为first未被初始化,1为first被初始化
int flag2 = 0;//0为second未被初始化,1为second被初始化
int flag3 = 0;//为0 表示third没有被初始化
for (int i = 0; i < numsSize; i++) //遍历数组
{
if ((flag3 ==0||nums[i] >third)&&nums[i]!= second) //third未被初始化或当前值比third大并且当前值不等于second
{
if ((flag2 ==0||nums[i] > second)&&nums[i]!= first) //second未被初始化或当前值比second大并且当前值不等于first
{
if (flag1 ==0||nums[i] > first) //值比first大的情况
{
if (flag2 == 1) //如果second已经被初始化了,那third也要在这一层被初始化
{
flag3 = 1;
}
if (flag1 == 1) //如果first被初始化了,那second也要在这一层被初始化
{
flag2 = 1;
}
third = second; //比first 大
second = first;
first = nums[i];
flag1 = 1; //first被当前值初始化
}
else
{
if (flag2 == 1)
{
flag3 = 1;
}
third = second; //比second大,没有first大
second = nums[i];
flag2 = 1;
}
}
else if (nums[i] != first) //说明不满足(flag2 ==0||nums[i] > second)即second被初始化了,但是当前遍历值还小于second
{
third = nums[i]; //比second小,比third大
flag3 = 1;
}
}
}
if (flag3 == 0) //说明没有第三大的数字
return first;
return third;
}
13 中心索引
int pivotIndex(int* nums, int numsSize){
if (numsSize == 0)
return -1;
if (numsSize == 1)
{
return 0;
}
int cur = 0;
int leftSum = 0;
int rightSum = 0;
while (cur<numsSize)
{
rightSum = rightSum + nums[cur];
cur++;
}
rightSum = rightSum-nums[0];
for (cur = 0; cur < numsSize; cur++)
{
if (leftSum == rightSum)
{
return cur;
}
else
{
if (cur >= numsSize - 2)
{
rightSum = 0;
}
else{
rightSum = rightSum - nums[cur + 1];
}
leftSum = leftSum + nums[cur];
}
}
return -1;
}
14 加一(数组存只能单个数字,整体加一,完成进位)
digits[digitsSize - 1] = digits[digitsSize - 1] + 1;
int i = digitsSize - 1;
int j = 0;
while (digits[i] == 10)
{
if (i == 0)
{
digits[i] = 0;
int* pre = (int*)malloc((digitsSize + 1)*sizeof(int));
pre[0] = 1;
for (j = 1; j < digitsSize + 1; j++)
{
pre[j] = digits[j - 1];
}
*returnSize = digitsSize + 1;
return pre;
}
digits[i - 1] = digits[i - 1] + 1;
digits[i] = 0;
i--;
}
*returnSize = digitsSize;
return digits;
15 两数之和(数组中找出和为目标值的两个整数)
//1、暴力解法O(n^2)
int* twoSum(int* nums, int numsSize, int target, int* returnSize)
{
int* returnpre = (int*)malloc(numsSize*sizeof(int));
for (int i = 0; i < numsSize; i++)
{
for (int j = i + 1; j < numsSize; j++)
{
if (nums[i] + nums[j] == target)
{
returnpre[0] = i;
returnpre[1] = j;
}
}
}
return returnpre;
}
//2、优质解法,散列数组
#define 2000
int* twoSum(int* nums, int numsSize, int target, int* returnSize)
{
int i = 0;
int hash[MAXSIZE];
int *ret = (int*)malloc(sizeof(int)* 2);
memset(hash, -1, sizeof(hash));
for (i = 0; i < numsSize; i++)//找
{
if (hash[(target - nums[i] + MAXSIZE) % MAXSIZE] != -1) //先找再赋值,可以避免找到自身的情况
{
ret[0] = i;
ret[1] = hash[(target - nums[i] + MAXSIZE) % MAXSIZE];
break;
}
hash[(nums[i] + MAXSIZE) % MAXSIZE] = i;
}
*returnSize = 2;
return ret;
}
思路说明
构造散列数组:
1.将nums数组元素和下标交换构造hash数组,初始赋值全为-1,因为nums数组的下标里不可能有-1。
2.给定MAXSIZE作为hash数组的元素个数,当遇到nums数组的负值时,用MAXSIZE+nums[i],把他放到数组后部分;(nums[i]+MAXSIZE)%MAXSIZE
可以让正数不变,负数+MAXSIZE。
3.可能会发生散列冲突,比如nums里有两个及以上相同值,==该值所在的hash数组的对应下标位置(原nums[i]的元素值)的元素值(原nums[i]的下标i)会始终被赋值为最后一次出现该值的nums下标。==但是被覆盖一个位置不影响计算。覆盖两个位置就会无法完整计算,这种情况只能构造更好的散列数组来避免,目前没有彻底的解决方法。