Jerry's Blog

Recording what I learned everyday

View on GitHub


12 July 2019

Angular (28) -- Angular Modules

by Jerry Zhang

LeetCode Day 7: P107. Binary Tree Level Order Traversal (Easy)

题目

一个二叉树,从下到上,从左到右返回各层节点。每层节点都放在一个数组里,最后把每一层都放在一个大数组里。

[
  [15,7],
  [9,20],
  [3]
]

我的思路:

从根节点往下,把每一层的所有节点,都加到List的前头, 也就是从后往前添加。这样最后的叶节点就会在List最前面。

我的算法:

做的时候发现,树的层次遍历忘记了。。。需要复习一下。

层次遍历需要一个Queue。

书里的算法:

把根节点存到Queue里
While ( Q 不空) {
    p = Q.dequeue() // 从Q中取出来一个元素然后进行需要的操作
    for each child c in children(p) do // 把P的所有子元素存到队列中。
        Q.enqueue(c)
}

看答案

class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            List<Integer> temp = new ArrayList<>();
            int cnt = queue.size();
            for (int i = 0; i < cnt; i++) {
                TreeNode cur = queue.poll();
                temp.add(cur.val);
                if (cur.left != null) queue.add(cur.left);
                if (cur.right != null) queue.add(cur.right);
            }
            res.add(0, temp);
        }
        return res;
        
    }
}

大体上是书里的算法。之前我的难点在于,不知道怎样记录节点的层级。因为每当完成一层,需要进行一次“结算”,把这层的这个数组存到大数组里。 一开始我想用一个counter,或者每个节点都附带一个层级。但那样就太麻烦了。 这个算法通过在外层while循环里面套一个for循环,看当前Queue的长度。Queue的长度就是这一层节点的个数。把Queue中的每个节点“弹出”,存 到临时数组中,再把其子节点添加到Queue里。for循环结束时,这一层也就遍历完了,把临时数组加到大数组里。

我的代码:

public class E_107_BinaryTreeLevelOrderTraversal {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);

        while (!queue.isEmpty()) {
            List<Integer> temp = new ArrayList<>();
            int cnt = queue.size();
            for (int i = 0; i < cnt; i++) {
                TreeNode node = queue.poll();
                temp.add(node.val);
                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
            }
            res.add(0, temp);
        }
        return res;
    }
}

坑:

queue的size一定要在for循环以前取出来,否则进了循环,queue的size是变化的,肯定出bug

最优解法:

 class Solution {
   public List<List<Integer>> levelOrderBottom(TreeNode root) {
     if (root == null) {
       return new ArrayList<>();
     }
     List<List<Integer>> result = new ArrayList<>();
     isLeaf(root, 0, result);
     return result;
   }
   
   private void isLeaf(TreeNode node, int depth, List<List<Integer>> list) {
     if (node != null) {
       if (list.size() > depth) {
         list.get(list.size() - 1 - depth).add(node.val);
       } else {
         List<Integer> temp = new ArrayList<>();
         temp.add(node.val);
         list.add(0, temp);
       }
       isLeaf(node.left, depth + 1, list);
       isLeaf(node.right, depth + 1, list);
     }
   }
 }

Angular

Shared Modules

If we have some components are the same in multiple modules, we can use a shared module, then import into other modules.

@NgModule({
  declarations: [
    AlertComponent,
    LoadingSpinnerComponent,
    DropdownDirective
  ],
  imports: [
    CommonModule
  ],
  exports: [
    AlertComponent,
    LoadingSpinnerComponent,
    DropdownDirective,
    CommonModule
  ]
})
export class SharedModule {

}

Then in other modules, we can import this shared module, and we get all the components in the shared module.

Core Modules

We can use core module to put some services in it to make the app module cleaner. A better way is to declare the service in the @injectable.

@NgModule({
  providers: [
    ShoppingListService,
    RecipeService,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptorService,
      multi: true
    }
  ]
})
export class CoreModule {
  
}

Lazy Loading

Only load the module based on the user visit.

Important: For lazy loading to work, your feature module needs to have its own routes.

const routes: Routes = [
  {
    path: '',
    component: RecipesComponent,
    canActivate: [AuthGuard],
    ...
  }
];
const appRoutes: Routes = [
  { path: '', redirectTo: '/recipes', pathMatch: 'full' },
  { path: 'recipes', loadChildren: './recipes/recipes.module#RecipesModule' }
];

or

const routes: Routes = [
    { path: '', redirectTo: '/recipes', pathMatch: 'full' },
    {
      path: 'recipes',
      loadChildren: () => import('./recipes/recipes.module').then(m => m.RecipesModule)
    }
  ];

We didn’t add a component after the path, instead, we use loadChildren. It means please only load this module when a user visits this path here. We not only need to add the path, but also need to pass the name of this module.

Now, the code is split and everything at this path will be put into a separate code bundle which is then downloaded and parsed on demand.

Preloading Lazy-loaded Code

Go to root router module, app-routing.module.ts, and set the preloadingStrategy.

@NgModule({
  imports: [RouterModule.forRoot(appRoutes, {preloadingStrategy: PreloadAllModules})],
  exports: [RouterModule]
})

This will preload the modules in idle time.

tags: Angular