1、关于size:
最好不要用for(i = 0; i <a.size();i++),而用for(i = 0 ; i <size;i++),因为a.size(),对于数据结构来说,运行过程中可能会改变大小,比如栈会出栈入栈。所以用变量存储初始大小。
2、关于矩阵:
顺时针旋转:沿左斜轴翻转,再沿竖中轴线翻转。
for i = 0 to size
for j = i+1 to size
array[i][j] = array[j][i]
for i = 0 to size
for j = 0 to size>>1 注意这里没有等号,如果有等号在偶数层多翻转一次。
array[i][j] = array[i][size - 1 - j]
同理,顺时针旋转:沿右斜轴翻转,再沿竖中轴线翻转。
顺时针180:直接沿横中轴翻转即可。
3、螺旋矩阵:
用四个变量标志上下左右的限,限的改变意味着转向。而用另外的变量作为遍历变量。
up = 0, down = n - 1,left = 0, right = n - 1,number = 1
while(number<= n*n)
for(j = left :right) //右侧有等号
array[up][j] = number++
up++
for(i = up : down) //有等号
array[i][right] = number++
right--
for(j = right : left)
array[down][j] = number++
down--
for(i = down : up)
array[i][left] = number++
left++
4、矩阵
从左下或右上开始,只需要O(m+n)的时间复杂度。
5、Trie树
struct Trie
{
vector<Trie*> children;//每个节点预备26个指针,分别指向26个字符;
bool isEnd;//该节点是否为end节点?即,该串是否contian?
}
Trie():
insert(word)
{ Trie* node = this;
for auto c: word
if(node->children[c-'a'] =NULL) node->children[c-'a'] = new Trie();//需要将字符新建一下
node = node->children[c-'a']
node->isEnd = true//否则会把初始节点的isEnd设为true
}
search(word)
{
Trie* node = this;
for auto c: word
if(node->children[c-'a'] =NULL) return false;//需要将字符新建一下
node = node->children[c-'a']
return node->isEnd = true//否则会返回初始节点的isEnd
//如果是找prefix,直接 return true即可。
}
6、最长回文子串
出现偶数字的字符;出现奇数次字符,其频次为1;
7、找环形链表入口:
快慢指针,fast 、 slow重合时不一定为入口,根据计算,重合地举例链表入环点(b-a)处。
p=head
while(p!=fast)
p = p->next,fast = fast->next;
//p走长度a,fast走长度a,刚好重合
8、链表:两数相加
while(l1||l2)
{
a = 0 or l1.val
b = 0 or l2.val
number = a+b+c
c= number/10
number = number%10
if(head == NULL)
head = tail = new(number)
else
tail->next = new (number)
tail = tail->next
}
if(c) tail = new (c)
9、链表相交
while(p!=q)
if(p==NULL) p = headB;
else p = p->next;
if(q==NULL) q = headA;
else q = q->next;
注意p = p->next是else的情况下,也就是,转向也等同于是next;
10、string s ="i am a pretty gril."按空格划分的方法:
stringstram s_stream(s);
vector<string> a;
string temp;
while(getline(s_stream,temp,' '))
a.push_back(temp);
注意:这里需要两个map。如果是一个char->string的映射可能会存在误判。
11、
放一个stack记录整个链表指针,每次从顶端弹出一个顶点,用于记录当前未排序的末尾节点。
while(i<size/2)
next=p->next
top=stack.top()
if(top == next)
next->next =NULL;
return;
p->next = top
top->next = next
p = next
endwhile
if(size%2) p->next = NULL
注意奇偶个数不同,循环结束条件不同
12、迭代器删除
for(auto it = s.begin();it!=s.end();)
if(*it == ' ')
s.erase(it);
else
it++;
注意这里,for循环没有每次执行it++,而是把it++放在循环体内部。
13、关于堆:
如果index是从0开始,那么堆应该是i,2*i+1和2*i+2
void build(int[] nums,int heapsize)
for(i = heapsize/2 -1 ;i>=0;i--)
heaply(nums,i,heapsize)
void heaply(int [] nums,int i,int heapsize)//从位置i开始的父子节点一定满足堆关系
int left = i*2+1,right = i*2+2,big = i;
while true
if(left<heapsize&&nums[left]>nums[big])
big = left
if(right<heapsize&&nums[right]>nums[big])
big = right
if(big!=i)
swap(nums[big],nums[i])
i = big
else
break
void findTopK(int nums,int size,int k)//
for(int i = 0 ; i<k-1;i++)//注意这里是<k-1,如果是top1不需要删除,所以第k大需要删除k-1个
size --
swap(nums[0],nums[i])
heaply(nums,0,size)
return nums[0]
14、回溯的其他方法:
size = nums.size()
vector<int> temp;
for(mask = 0 :(1<<size))
for(i = 0 :size)
if(mask&(1<<i))
temp.push_back(nums[i]);
result.push_back(temp);
15、Boyer-Moore
找非负数组元素中过半元素,用一个count记录当前出现次数
int count = 0,result = -1
for(i : nums)//nums是数组
if(i == result) count++;
else if(--count < 0 ) count = 1,candidate = i;
16、堆
pritority_queue qe;
sum = 0,ans = 0;
for(i:nums)
sum+=i
if(i<0)
qe.push(-i)
if( sum < 0)
sum+=qe.top();
qe.pop();
ans++;
17、取反思想
for (i:nums)
temp+=i
if(map.count(temp - k)!=0) result+=map[temp-k];
map[temp-k]++;
18、进制转换
问:给定rand函数是从1~7的随机数,如何生成1~10的随机数
用两个1~7的随机数生成2位7进制数,将其转换为10进制,也就是00~48。舍弃末尾的9位后,对00~39取余即可。
同理:用k进制的随机数生成m进制的随机数:看几位k进制可以包含m,再转换为m进制后舍弃部分并取余即可。
19、图-用入度和出度解决问题:
20、用分半的思想(或者还是说堆更合适)
用两个优先队列。priority_queue<int,vector<int>,greater<int>>表示按从大到小排列的数据,存放较小的数据。而priority_queue<int,vector<int>,less<int>>表示从小到大排列的数据,存放较大的数据。
如果两个队列的大小相等,那么中位数是两个队列的top/2;如果两个队列大小不等,在较大的队列的头部。
21、
在数据量较大时,如果一个一个用f(n-1)*x时一定会超时。
做法:考虑特殊情况(例如n为-2147483648),此外用n每个2进制位计算结果的幂;
n =(n<0)? -n : n
result = 1
while(n)
if(n%2) result*=x
x*=x
n>>=1
return result或者1.0/result