1.二叉树平均值
大概题目意思:记录二叉树每一层的平均值
解法:采用队列,每次先获取队列中的点个数,然后遍历这几个点,记录值,并且将每个点的左右结点(如果有)入队,这样就完成了一层的纪录,队列为空后,记录完毕。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
queue<TreeNode*> que;
vector<double> ans;
que.push(root);
int size;
double sum=0;
TreeNode* node;
while(!que.empty()){
size=que.size();
for(int i=1;i<=size;i++){
node=que.front();
que.pop();
sum+=node->val;
if(node->left!=NULL)que.push(node->left);
if(node->right!=NULL)que.push(node->right);
}
ans.push_back(sum/size);
sum=0;
}
return ans;
}
};
2.多少小于当前数字的数字
思路1:暴力枚举,时间n2
思路2:二维数组,一重记录值,一重记录原数组的顺序,然后sort,sort完设置一个pre指针遍历,pre的值就是答案,时间nlog2n
class Solution {
public int[] smallerNumbersThanCurrent(int[] nums) {
int n=nums.length;
int pre=-1;
int []res=new int [n];
int [][]set=new int[n][2];
for(int i=0;i<n;i++)
{
set[i][0]=nums[i];
set[i][1]=i;
}
Arrays.sort(set, new Comparator<int []>(){
public int compare(int data1[],int data2[]){
return data1[0]>data2[0]?1:-1;
}
});
for(int i=0;i<n;i++){
if(pre==-1||set[i][0]!=set[i-1][0])
pre=i;
res[set[i][1]]=pre;
}
return res;
}
}
思路3:计数排序,然后一个for循环叠加起来,此时数组里的前一个位置的值就是答案,注意当原数组中如果有0的数据,此时必须加一个特判,否则越界
class Solution {
public int[] smallerNumbersThanCurrent(int[] nums) {
int n = nums.length;
int [] cnt = new int [101];
int [] res = new int [n];
for(int i=0;i<n;i++)
cnt[nums[i]]++;
for(int i=1;i<101;i++)
cnt[i]+=cnt[i-1];
for(int i=0;i<n;i++)
res[i]=nums[i]==0?0:cnt[nums[i]-1];
return res;
}
}
3.二叉树先序遍历
思路1:递归,注意这里List是接口
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> List =new ArrayList<Integer>();
dfs(root,List);
return List;
}
public void dfs(TreeNode root,List List){
if(root==null)return;
List.add(root.val);
dfs(root.left,List);
dfs(root.right,List);
}
}
思路2:栈。每次拿到一个节点,先取值然后向左边迭代直至为空,之后弹出取右边。拿到右边也是重复向左迭代直至为空的操作
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> List =new ArrayList<Integer>();
Stack<TreeNode>stack = new Stack<TreeNode>();
TreeNode t;
if(root==null)return List;
t=root;
while(!stack.empty()||t!=null){
while(t!=null){
List.add(t.val);
stack.push(t);
t=t.left;
}
t=stack.pop();
t=t.right;
}
return List;
}
}
4.每个数字出现的次数是否独一无二
思路 :用map记录个数,然后遍历map把value加入set,然后比较长度
注意:set或者map读取长度用的size是一个函数,需要加(),并非数组直接length
class Solution {
public boolean uniqueOccurrences(int[] arr) {
Map<Integer,Integer> map= new HashMap<Integer,Integer>();
for(int i : arr)
map.put(i,map.getOrDefault(i,0)+1);
Set<Integer>set = new HashSet<Integer>();
for(Map.Entry<Integer,Integer> entry : map.entrySet())
set.add(entry.getValue());
return set.size()==map.size();
}
}
5.求根到叶子节点的数字之和
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int sumNumbers(TreeNode root) {
return dfs(root,0);
}
int dfs(TreeNode root,int val){
if(root==null)return 0;
val=val*10+root.val;
if(root.left==null&&root.right==null)return val;
else return dfs(root.left,val)+dfs(root.right,val);
}
}
6.岛屿的周长
思路1:遍历每一个点,然后遍历它的四个方向的点,如果越界或者为水,则ans++
class Solution {
public int islandPerimeter(int[][] grid) {
int[] dx={-1,1,0,0};
int[] dy={0,0,1,-1};
int n=grid.length;
int m=grid[0].length;
int ans=0;
int x1,y1;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(grid[i][j]==1)
for(int k=0;k<4;k++){
x1=i+dx[k];
y1=j+dy[k];
if(x1<0||y1<0||x1>=n||y1>=m||grid[x1][y1]==0)ans+=1;//一条边如果被算进来,这条边不会再被重复计
}
}
return ans;
}
}
思路2:dfs
class Solution {
int[] dx={-1,1,0,0};
int[] dy={0,0,1,-1};
public int islandPerimeter(int[][] grid) {
int n=grid.length;
int m=grid[0].length;
int ans=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(grid[i][j]==1)
ans+=dfs(i,j,grid,n,m);
}
return ans;
}
int dfs(int x,int y,int[][]grid,int n,int m){
int ret=0;
if(x<0||y<0||x>=n||y>=m||grid[x][y]==0)return 1;
if(grid[x][y]==2)return 0;//放前面可能会数组越界
grid[x][y]=2;
int x1,y1;
for(int k=0;k<4;k++){
x1=x+dx[k];
y1=y+dy[k];
ret+=dfs(x1,y1,grid,n,m);
}
return ret;
}
}
2021/3/4
7.反转链表
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode*p=head;
ListNode* temp=NULL;
ListNode* tail=NULL;
while(p!=NULL){
temp=new ListNode(p->val);
temp->next=tail;
tail=temp;
p=p->next;
}
return tail;
}
};
思路1(自己做法):遍历链表,然后每遇到一个节点都进行new,把该新节点指向tail,并且不断更新tail,需要耗费内存
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode*p=head;
ListNode* nextTemp=NULL;
ListNode* preTemp=NULL;
while(p!=NULL){
nextTemp=p->next;
p->next=preTemp;
preTemp=p;
p=nextTemp;
}
return preTemp;
}
};
思路2 遍历每一个节点的时候记录更新前一个节点和后一个节点,然后改next即可,可以不耗费内存
8.两数之和
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int,int> ma;
for(int i=0;i<nums.size();i++)
ma[nums[i]]=i+1;
for(int i=0;i<nums.size();i++){
if(ma[target-nums[i]]&&ma[target-nums[i]]!=i+1)
return {i,ma[target-nums[i]]-1};
}
return {};
}
};
思路 这题卡了好久,首先我一开始没有判断遍历时候的对应点是否是原点(题目数组中有重复元素),然后这个问题可以通过记录下标来解决。也可以一遍哈希,先找对应点再存储当前点,因为如果答案存在,这个点是会被再度遍历的。
9.剪绳子
思路1:数学,用数学方法证明当每段的长度为3的时候,结果最大。然后根据余数和商返回结果
class Solution {
public:
int cuttingRope(int n) {
if(n<=3)return n-1;//n为3必须特判,因为题目要求绳子必须剪
int a=n/3;
int b=n%3;
if(b==0)return pow(3,a);
else if(b==1)return pow(3,a-1)*4;
else return pow(3,a)*2;
}
};
思路2:动态规划,dp[i]代表长度为i的绳子经过剪去处理后能够得到的最好结果,可以获得dp方程:
for j 2 to i-2 //两段必须长度都大于2才有意义
dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]))
注意j的范围,还是让它可以等于i,否则当n=3的时候循环进不去
class Solution {
public:
int dp[202]={0};
int cuttingRope(int n) {
dp[2]=1;
for(int i=3;i<=n;i++){
for(int j=2;j<=i;j++){
dp[i]=max(dp[i],max(j*(i-j),j*dp[i-j]));
}
}
return dp[n];
}
};
10.二叉树是否对称
对于每一对对称的节点,
1.L=R
2.LL=RR
3.LR=RL
class Solution {
public:
bool isMirror(TreeNode*L,TreeNode*R){
if(L==NULL&&R==NULL)return true;
else if(L==NULL||R==NULL||L->val!=R->val)return false;
return isMirror(L->left,R->right)&&isMirror(L->right,R->left);
}
bool isSymmetric(TreeNode* root) {
if(root==NULL)return true;
return isMirror(root->left,root->right);
}
};
11.判断后序遍历序列是否为二叉搜索树
后序遍历这一块还是好说,主要是判断二叉搜索树这里卡住了。在找到mid节点之后,继续利用这个mid节点,如果他能走到相应位置,则为二叉搜索树,否则错误。判断的时候可以往根节点地方走会简便一些,我这里刚好是反方向
class Solution {
public:
bool dfs(vector<int>& postorder,int left, int right){
if(left>=right)return true;//大于的情况是有单个孩子的情况,模拟一下可知
int mid=right;
while(mid>=left&&postorder[mid]>=postorder[right])mid--;
int tempmid=mid;
while(tempmid>=left&&postorder[tempmid]<postorder[right])tempmid--;//如果是二叉搜索树,该指针最后会比left小1
return left-tempmid==1&&dfs(postorder,left,mid)&&dfs(postorder,mid+1,right-1);
}
bool verifyPostorder(vector<int>& postorder) {
return dfs(postorder,0,postorder.size()-1);
}
};
12.最长不含重复字符子字符串
思路: 双指针+哈希映射定位左指针
让右指针一直往右边移动,当出现出现的字符在map中时候(可能不在当前区间,这个用max处理),让i定位到记录的字符之后一位
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int i=0,j=0;
int ans=0;
map<char,int> M;
while(j<s.size()){
if(M.find(s[j])!=M.end()){
i=max(i,M[s[j]]+1);//这里用max是因为可能M中的这个s[j]并不在区间内
}
M[s[j]]=j;
ans=max(ans,j-i+1);
j++;
}
return ans;
}
};