1.二叉搜索树与双向链表
时间限制:1秒 空间限制:32768K 热度指数:156582
题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
解题思路:
- 在二叉搜索树中,每个节点都有两个指向子结点的指针。在双向链表中,每个节点也有两个指针,分别指向前一个结点和后一个节点。
- 将二叉搜索树转换成排序双向链表时,原先指向左子结点的指针调整为链表中指向前一个结点的指针,原先指向右子节点的指针调整为链表中指向后一个节点的指针
- 可以将二叉搜索树看成三部分,前面部分(左子树)的值均小于根节点,后面的部分(右子树)均大于根节点,根据这种特性,可以采取中序遍历
- 根据中序遍历,我们可以将其按照从小到大的顺序排列好
- 将左子树按照中序遍历转换成排序双向链表,右子树也是同理,然后根节点10将值为8的结点与自己链接起来,接着将右子树最小的节点12和根节点链接起来
- 如何转换它的左右子树呢?可以采取递归的方式
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
if(!pRootOfTree) return NULL;
TreeNode* p = NULL;
help(pRootOfTree,p);
while(pRootOfTree->left){
pRootOfTree = pRootOfTree->left;
}
return pRootOfTree;
}
void help(TreeNode* cur,TreeNode*& pre){
if(!cur) return;
help(cur->left,pre);
if(pre) pre->right = cur;
cur->left = pre;
pre = cur;
help(cur->right,pre);
}
};
2.字符串的排列
时间限制:1秒 空间限制:32768K 热度指数:241299
本题知识点: 字符串
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
解题思路:
- 把字符串分成两部分:一部分是字符串的第一个字符
- 另一部分是第一个字符以后的所有的字符,然后求该部分的字符排列
- 然后拿第一个字符和它后面的字符逐个交换
# -*- coding:utf-8 -*-
import itertools
class Solution:
def Permutation(self, ss):
# write code here
if not ss:
return []
return sorted(list(set(map(''.join, itertools.permutations(ss)))))
3.数组中出现次数超过一半的数字
时间限制:1秒 空间限制:32768K 热度指数:210161
本题知识点: 数组
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解题思路:
- 我们可以在遍历数组的时候保存两个值:一个是数组中的一个数字,另一个是次数
- 当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加一;否则次数减1
- 如果次数减为0,说明不是我们要找的数字,这时就需要保存下一个数字,并将次数重新设置为1
- 因为我们要找的数字超过数组长度的一半,那么如果最后哪个数字的次数减为1那么该数字就是我们要找的数字
# -*- coding:utf-8 -*-
class Solution:
def MoreThanHalfNum_Solution(self, numbers):
# write code here
if not numbers:
return 0
result = numbers[0]
times = 1
length = len(numbers)
for i in range(1, length-1):
print times
if times == 0:
result = numbers[i+1]
elif result == numbers[i+1]:
times += 1
else:
times -= 1
if numbers.count(result)*2 > length:
return result
return 0
4.最小的K个数
时间限制:1秒 空间限制:32768K 热度指数:268814
本题知识点: 数组
题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,
解题思路:
解法一:(时间复杂度为O(n), 只有当我们可以修改输入的数组时可用)
- 基于数组的第K个数字来调整,使得比第K个数字小的所有数字都位于数组的左边
- 使得比第K个数字大的所有数字都位于数组的右边
- 这样调整后,位于数组中左边的K个数字就是最小的K个数字,但是序列不一定是排序的
class Solution {
public:
int partion(vector<int>& input, int beg, int end)
{
int key = input[beg];
while (beg < end)
{
while (beg < end && input[end] >key)
end--;
input[beg] = input[end];
while (beg < end && input[beg] <= key)
beg++;
input[end] = input[beg];
}
input[beg] = key;
return beg;
}
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
if (input.size() == 0 || input.size() < k || k <= 0)
return {};
int low = 0;
int high = input.size()-1;
int pos = partion(input, low, high);
while (pos != k - 1)
{
if (pos > k - 1)
{
high=pos-1;
pos = partion(input, low, high);
}
else
{
low=pos+1;
pos = partion(input, low, high);
}
}
vector<int> res(input.begin(), input.begin() + k);
return res;
}
};
解法二;(时间复杂度为O(nlogk)的算法,特别适合处理海量数据)
- 我们可以创建一个大小为K的数据容器来存储最小的K个数字,接下来每次从输入的n个整数中读入一个数
- 如果容器中已有的数字小于K个,则直接放入容器;如果容器中已有K个数字,此时我们已经不能插入而是应该替换了
- 这时就要找出容器中的最大值,然后将最大值与待插入的数字进行比较
- 如果小,就替换当前的最大值;如果大,就不替换,继续和下一个即将插入的数字进行比较
- 这个容器我们可以使用堆·
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int len = input.size();
vector<int> result;
if(len <= 0 || k <= 0 || len < k)
return result;
for(int i = 0;i < k; ++i)
result.push_back(input[i]);
make_heap(result.begin(),result.end());
for(int i= k;i < len; ++i)
if(result[0] > input[i]){
pop_heap(result.begin(),result.end());
result.pop_back();
result.push_back(input[i]);
push_heap(result.begin(),result.end());
}
sort_heap(result.begin(),result.end());
return result;
}
};
5.连续子数组的最大和
时间限制:1秒 空间限制:32768K 热度指数:148691
本题知识点: 数组
题目描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
解题思路:
- 此处以数组{1,-2,3,10,-4,7,2,-5}为例
- 前面的就不赘述了,表格里面有,我们从3开始分析,此时得到的和为3,(表格里面)第四步加10,和为13
- 第五步加-4,和为9,小于前面的13,将其保存下来,有可能就是最大的
- 第六步加7,和为16,比13大
- 第七步加2,和为18,比16大
- 第八步加-5,和为13,小于18,所以18就是最大值,对应的连续子数组为{3,10,-4,7,2}
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
if(array.size() <= 0)
return 0;
int currentSum = arAray[0];
int maxSum = array[0];
int len = array.size();
for(int i = 1; i < len; ++i)
{
currentSum += array[i];
if(currentSum < array[i])
currentSum = array[i];
if(currentSum > maxSum)
maxSum = currentSum;
}
return maxSum;
}
};
6.整数中1出现的次数(从1到n整数中1出现的次数)
时间限制:1秒 空间限制:32768K 热度指数:117393
题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
解题思路:
(一)采取暴力解决,效率比较低下,时间复杂度为O(nlogn)
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
int count = 0;
if(n <= 0)
return 0;
for(int i = 1; i <= n; ++i)
{
int temp = i;
while(temp)
{
if(temp % 10 == 1)
count++;
temp = temp /10;
}
}
return count;
}
};
(二)
# -*- coding:utf-8 -*-
class Solution:
def NumberOf1Between1AndN_Solution(self, n):
# write code here
'''
思路:X∈[1,9],0不适用
从 1 至 10,在它们的个位数中,任意的 X 都出现了 1 次。
从 1 至 100,在它们的十位数中,任意的 X 都出现了 10 次。
从 1 至 1000,在它们的百位数中,任意的 X 都出现了 100 次。
依此类推,从 1 至 10^i ,在它们的左数第二位(右数第 i 位)中,任意的 X 都出现了 10^(i−1) 次。
'''
x=1
if n<0 or x<=0 or x>9:
return 0
high=-1;low=-1;time=0
i=1#i为数字n从右往左的第i位
while high!=0:
high = n / (10 ** i) # 拿到高位
temp = n % (10 ** i)
occur = temp / (10 ** (i - 1)) # 拿到第i位上的数字
low = n % (10 ** (i - 1))#拿到i的低位
time+=high*(10**(i-1))#先算基础值,再加上低位的进行补充
if occur>x:#比x大,把第i位的次数加上
time=time+10**(i-1)
elif occur==x:
time=time+low+1
i+=1
return time