一般的题
第一个只出现一次的字符
题目描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)
思路
方式1.使用map hash
方式2.使用数组哈希count[128]
方式3.使用两个bitset<128>b1,b2;进行标记;
bitset<128>说明其键是128位的。
1)遍历字符串,当前字符为c,若c第一次出现,则b1[c]=0,置b1[c]=1,表示出现过。若c出现第二次,则b1[c]&&!b2[c]==1,即b1[c]=1,b2[c]=0,置b2[c]=1;
2)再次遍历字符串,若b1[c]&&b2[c]==1,说明c出现不止一次;
class Solution {
public:
// 方式1.
int mapHash(string str){
map<char,int>count;
for(int i=0;i<str.size();i++){
count[str[i]]++;
}
for(int i=0;i<str.size();i++){
if(count[str[i]]==1){
return i;
}
}
return -1;
}
// 方式2
int arrayHash(string str){
int count[128] = {0};
for(int i=0;i<str.size();i++){
count[str[i]]++;
}
for(int i=0;i<str.size();i++){
if(count[str[i]]==1){
return i;
}
}
return -1;
}
// 方式3
int bitsetCount(string str){
bitset<128> b1,b2; // 默认值为0,b1为1 说明出现过 b2为1 说明出现不止1次
for(int i=0;i<str.size();i++){
if(!b1[str[i]]&&!b2[str[i]]){
// b1 b2都为0说明是第一次出现
b1[str[i]] = 1;
}else if(b1[str[i]]&&!b2[str[i]]){
// b1 为1 b2为0 说明出现过了
b2[str[i]] = 1;
}
}
for(int i=0;i<str.size();i++){
if(b1[str[i]]&&!b2[str[i]]){
// 统计完 b1为1 b2为0 说明只出现1次
return i;
}
}
return -1;
}
int FirstNotRepeatingChar(string str) {
/*
1.方法一、map哈希
2.方法二、由于全部由字母组成 可以使用128个元素的计数器数组 字符char可以直接作为数组的下标
3.方法三、128位的bitset【二值集合】bitset<128>
*/
//return mapHash(str);
//return arrayHash(str);
return bitsetCount(str);
}
};
把数组排成最小的数
题目描述
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
思路
数组中的数有可能是1位数,也有可能是2位数等多位数。
考虑使用STL的sort排序,设置cmp规则。
将数组前后两个整型数 a ,b 转换成string后拼接,再转换成longlong,按结果更小的排序
class Solution {
public:
static bool cmp(int a, int b){
string as = to_string(a);
string bs = to_string(b);
// 应该是先拼接 在计算拼接后字符的大小
return stol( as + bs) < stol(bs + as);
}
string PrintMinNumber(vector<int> numbers) {
sort(numbers.begin(),numbers.end(),cmp);
string res = "";
for(int i=0;i<numbers.size();i++){
res+=to_string(numbers[i]);
}
return res;
}
};
删除链表中重复的节点
题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
思路
链表是排序的
关键要扫描到第一个非重复的节点
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
if(pHead==NULL)return NULL;
ListNode* res = new ListNode(pHead->val-1);
res->next = pHead;
ListNode* pre = res;
ListNode* cur = pHead;
while(cur){
// 【重点】这里一共有三个关键节点:pre cur 以及 cur->next
// pre不要动、 让cur 和 cur->next去除重复数字
if(cur->next!=NULL&&cur->next->val==cur->val){
cur = cur->next;
while(cur->next!=NULL&&cur->next->val==cur->val){
cur = cur->next;
}
cur = cur->next;// cur->next指向了与cur不同的数才出了上述循环
pre->next = cur;// 这里是pre->next=cur;而不是pre=cur;是假设当前的cur可能是个不重复的数
// 【巧妙】这里 需要一个if包裹这个while循环
}else{
// cur->next==NULL了 或者
// cur与cur->next不相等了 且cur不是重复的数
pre = pre->next; // pre = cur; 也行
cur = cur->next;
}
}
return res->next;
}
};
从尾到到尾打印链表
题目描述
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。
思路
方式1.借助栈存储节点,然后实现从后向前输出;或是借助vector以及它的reverse方法
方式2.递归方式,参考树的前中后序遍历的递归,先访问后面的节点,在访问当前的节点,再把当前的结果集res返回给上层调用,让上层放入上层访问的节点。
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
// 方式1.借助栈存储节点,然后实现从后向前输出
vector<int> method1(ListNode* head){
vector<int>res;
if(head==NULL)return res;
stack<int> ls;
ListNode* p = head;
while(p){
ls.push(p->val);
p = p->next;
}
while(!ls.empty()){
res.push_back(ls.top());
ls.pop();
}
return res;
}
// 方式2.递归方式,参考树的前中后序遍历的递归,先访问后面的节点,在访问当前的节点
vector<int> method2(ListNode* head){
vector<int>res;
if(head==NULL)return res; // 当访问到末尾空节点的时候,返回一个空的res
res = method2(head->next);// 最末尾返回一个空的res,
res.push_back(head->val); // 空的res放入倒数第一个节点,在返回给上一层
return res;
}
vector<int> printListFromTailToHead(ListNode* head) {
return method2(head);
}
};
反转链表
题目描述
输入一个链表,反转链表后,输出新链表的表头。
思路
方法一、使用栈维护链表节点
方法二、三个指针
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode *pre = nullptr;
ListNode *cur = pHead;
ListNode *nextOne = nullptr; // 初始化为nullptr, 循环里会再次赋值
while (cur) {
nextOne = cur->next; // 先找到下一个节点,防止丢失
cur->next = pre; // 当前节点的next指向前一个节点
pre = cur; // 当前节点变成下一轮的前驱节点
cur = nextOne ; // 下一个节点变成下一轮的当前节点
}
return pre;
}
};