Showing posts with label Cycle. Show all posts
Showing posts with label Cycle. Show all posts

LeetCode 957 - Prison Cells After N Days


https://leetcode.com/problems/prison-cells-after-n-days/
There are 8 prison cells in a row, and each cell is either occupied or vacant.
Each day, whether the cell is occupied or vacant changes according to the following rules:
  • If a cell has two adjacent neighbors that are both occupied or both vacant, then the cell becomes occupied.
  • Otherwise, it becomes vacant.
(Note that because the prison is a row, the first and the last cells in the row can't have two adjacent neighbors.)
We describe the current state of the prison in the following way: cells[i] == 1 if the i-th cell is occupied, else cells[i] == 0.
Given the initial state of the prison, return the state of the prison after N days (and N such changes described above.)
    Example 1:
    Input: cells = [0,1,0,1,1,0,0,1], N = 7
    Output: [0,0,1,1,0,0,0,0]
    Explanation: 
    The following table summarizes the state of the prison on each day:
    Day 0: [0, 1, 0, 1, 1, 0, 0, 1]
    Day 1: [0, 1, 1, 0, 0, 0, 0, 0]
    Day 2: [0, 0, 0, 0, 1, 1, 1, 0]
    Day 3: [0, 1, 1, 0, 0, 1, 0, 0]
    Day 4: [0, 0, 0, 0, 0, 1, 0, 0]
    Day 5: [0, 1, 1, 1, 0, 1, 0, 0]
    Day 6: [0, 0, 1, 0, 1, 1, 0, 0]
    Day 7: [0, 0, 1, 1, 0, 0, 0, 0]
    
    
    Example 2:
    Input: cells = [1,0,0,1,0,0,1,0], N = 1000000000
    Output: [0,0,1,1,1,1,1,0]
    

    Note:
    1. cells.length == 8
    2. cells[i] is in {0, 1}
    3. 1 <= N <= 10^9
    X.
    https://blog.csdn.net/GQxxxxxl/article/details/85040103
    观察可知第一位和最后一位数字一定会变成0,故只有中间六位数字,2**6=64,即最多有64种状态,一定会形成一种循环。取余求循环位置即可。
    一个很显然的观察是,两侧的格子在1天后都会变成空并且保持这个状态,所以实际上可以只考虑6个格子的状态。所以状态数量最多只有1+2^6种。不过当成2^8种来做也没什么问题。
    显然用线性算法在N=1e9的时候必然会超时。不过,观察到状态必然会重复之后,可以通过找到循环来解决问题。如果第i天的状态与第start天相同,那么循环节的长度为i - start,可以令N = (N - i) % (i - start),然后找到对应的天数的状态。
    我比赛的时候没有写N--,而是i = 0 to N-1,显然前一种比较利于取模,后一种比较麻烦。所以我在给N取模这一点上错了两次。
    另一个观察是[1],因为格子的数量是偶数,所以对于每一种状态,都可以找到一种合法的之前的状态,所以初始状态后一步就可以进入循环;而且循环节长度必然是1、7或14,所以可以在一步之后就按照14为循环节进行操作。
    We record all seen states.
    Be careful,
    we need transform array to string as the key,
    otherwise it use the reference.
    Java:
        public int[] prisonAfterNDays(int[] cells, int N) {
            Map<String, Integer> seen = new HashMap<>();
            while (N > 0) {
                int[] cells2 = new int[8];
                seen.put(Arrays.toString(cells), N--);
                for (int i = 1; i < 7; ++i)
                    cells2[i] = cells[i - 1] == cells[i + 1] ? 1 : 0;
                cells = cells2;
                if (seen.containsKey(Arrays.toString(cells))) {
                    N %= seen.get(Arrays.toString(cells)) - N;
                }
            }
            return cells;
        }
    

    https://blog.csdn.net/u013383813/article/details/85040454
    就算 是 T(N) 也会超时。
    所以 方法是 减少 相应的 计算 总量,即 N 转化为 n。
    考虑到 是一种规则变化,所以可以试试 看是否 是循环变化 ,即 存在 相应的 最小周期。

    由于 起始数组 ,nums[0] 和nums[7] 可能不为零,必不会成为 循环的一环,所以从 nums1(nums迭代一次)开始迭代,寻找相应的最小周期,然后 将N 简化为 n。

      public int[] prisonAfterNDays(int[] cells, int N) {
        int[] ocells = new int[cells.length];
        int[] fcells = new int[cells.length];
        for (int i = 1; i <= 6; i++) {
          ocells[i] = 1 - cells[i - 1] ^ cells[i + 1];
          fcells[i] = ocells[i];
        }
        int[] ccells = new int[cells.length];
        int cnt = 1;
        while (true) {
          for (int i = 1; i <= 6; i++)
            ccells[i] = 1 - fcells[i - 1] ^ fcells[i + 1];
          for (int i = 1; i <= 6; i++)
            fcells[i] = ccells[i];
          boolean isSame = true;
          for (int i = 1; i <= 6; i++) {
            if (ccells[i] != ocells[i]) {
              isSame = false;
              break;
            }
          }
          if (isSame)
            break;
          cnt++;
        }
        int n = (N - 1) % cnt;
        while (n-- > 0) {
          for (int i = 1; i <= 6; i++)
            ccells[i] = 1 - fcells[i - 1] ^ fcells[i + 1];
          for (int i = 1; i <= 6; i++)
            fcells[i] = ccells[i];
        }
        return fcells;


      }
    https://zxi.mytechroad.com/blog/uncategorized/leetcode-957-prison-cells-after-n-days/
    Time complexity: O(2^8)
    Space complexity: O(2^8)

    I tried to find the pattern of the loop.
    Well, the length of loop can be 1, 7, or 14.
    So once we enter the loop, every 14 steps must be the same state.
    The length of cells is even,
    so for any state, we can find a previous state.
    So all states are in a loop.
    It means that, after a single step from the initial state, we enter the loop.
    Java
        public int[] prisonAfterNDays(int[] cells, int N) {
            for (N = (N - 1) % 14 + 1; N > 0; --N) {
                int[] cells2 = new int[8];
                for (int i = 1; i < 7; ++i)
                    cells2[i] = cells[i - 1] == cells[i + 1] ? 1 : 0;
                cells = cells2;
            }
            return cells;
        }
    https://leetcode.com/problems/prison-cells-after-n-days/discuss/205700/Find-the-pattern
    https://blog.csdn.net/fuxuemingzhu/article/details/85032587
    写了一个多小时的题目,后来才发现周期是14.

    发现周期的过程就是尝试了一下,不同的数组的循环周期是多少。试了几个之后发现是14,那就是14了。

    如果知道是14之后那就好办了,先把N mod 14,然后注意了!如果mod完之后等于0,应该把N设置为14!!最后我是有时间提交通过的,但是这个地方没有想明白,所以比赛结束之后才通过的。

    底下的转移方程就很简单了,直接转移。因为最多操作14次,所以很容易就过了。
    https://blog.csdn.net/qq_17550379/article/details/85250138这是一个经典的细胞自动机问题,可以查看Leetcode 289:生命游戏(最详细的解法!!!)

    https://leetcode.com/articles/prison-cells-after-n-days/
    We simulate each day of the prison.
    Because there are at most 256 possible states for the prison, eventually the states repeat into a cycle rather quickly. We can keep track of when the states repeat to find the period t of this cycle, and skip days in multiples of t.
    Algorithm
    Let's do a naive simulation, iterating one day at a time. For each day, we will decrement N, the number of days remaining, and transform the state of the prison forward (state -> nextDay(state)).
    If we reach a state we have seen before, we know how many days ago it occurred, say t. Then, because of this cycle, we can do N %= t. This ensures that our algorithm only needs O(2**{\text{cells.length}}) steps.
    • Time Complexity: O(2^N), where N is the number of cells in the prison.
    • Space Complexity: O(2^N * N).
      public int[] prisonAfterNDays(int[] cells, int N) {
        Map<Integer, Integer> seen = new HashMap();

        // state = integer representing state of prison
        int state = 0;
        for (int i = 0; i < 8; ++i) {
          if (cells[i] > 0)
            state ^= 1 << i;
        }

        // While days remaining, simulate a day
        while (N > 0) {
          // If this is a cycle, fast forward by
          // seen.get(state) - N, the period of the cycle.
          if (seen.containsKey(state)) {
            N %= seen.get(state) - N;
          }
          seen.put(state, N);

          if (N >= 1) {
            N--;
            state = nextDay(state);
          }
        }

        // Convert the state back to the required answer.
        int[] ans = new int[8];
        for (int i = 0; i < 8; ++i) {
          if (((state >> i) & 1) > 0) {
            ans[i] = 1;
          }
        }

        return ans;
      }

      public int nextDay(int state) {
        int ans = 0;

        // We only loop from 1 to 6 because 0 and 7 are impossible,
        // as those cells only have one neighbor.
        for (int i = 1; i <= 6; ++i) {
          if (((state >> (i - 1)) & 1) == ((state >> (i + 1)) & 1)) {
            ans ^= 1 << i;
          }
        }

        return ans;

      }


    X. https://leetcode.com/problems/prison-cells-after-n-days/discuss/205684/JavaPython-Find-the-Loop-or-Mod-14
        public int[] prisonAfterNDays(int[] cells, int N) {
            while (N > 0) {
                N--;
                int[] cells2 = new int[8];
                for (int i = 1; i < 7; ++i)
                    cells2[i] = cells[i - 1] == cells[i + 1] ? 1 : 0;
                cells = cells2;
            }
            return cells;
        }
    
    This is right solution, but it will get TLE when N is big.
    Note that cells.length = 8, and cells[0] and cells[7] will become 0.
    In fact, cells have only 2 ^ 6 = 64 different states.
    And there will be a loop.

    Minimum number of swaps required to sort an array


    Related: Number of swaps to sort when only adjacent swapping allowed
    Minimum number of swaps required to sort an array - GeeksforGeeks
    Given an array of n distinct elements, find the minimum number of swaps required to sort the array.

    This can be easily done by visualizing the problem as a graph. We will have n nodes and an edge directed from node i to node j if the element at i’th index must be present at j’th index in the sorted array.
    a
    Graph for {4, 3, 2, 1}
    
    The graph will now contain many non-intersecting cycles. Now a cycle with 2 nodes will only require 1 swap to reach the correct ordering, similarly a cycle with 3 nodes will only require 2 swap to do so.
    b
    Graph for {4, 5, 2, 1, 5}
    
    Hence,


  1. ans = Σi = 1k(cycle_size – 1)

  2. where k is the number of cycles
    Time Complexity: O(n*log(n))
    Auxiliary Space: O(n)
        public static int minSwaps(int[] arr)
        {
            int n = arr.length;
            // Create two arrays and use as pairs where first
            // array is element and second array
            // is position of first element
            ArrayList <Pair <Integer, Integer> > arrpos =
                      new ArrayList <Pair <Integer, Integer> > ();
            for (int i = 0; i < n; i++)
                 arrpos.add(new Pair <Integer, Integer> (arr[i], i));
            // Sort the array by array element values to
            // get right position of every element as the
            // elements of second array.
            arrpos.sort(new Comparator<Pair<Integer, Integer>>()
            {
                @Override
                public int compare(Pair<Integer, Integer> o1,
                                   Pair<Integer, Integer> o2)
                {
                    if (o1.getValue() > o2.getValue())
                        return -1;
                    // We can change this to make it then look at the
                    // words alphabetical order
                    else if (o1.getValue().equals(o2.getValue()))
                        return 0;
                    else
                        return 1;
                }
            });
            // To keep track of visited elements. Initialize
            // all elements as not visited or false.
            Boolean[] vis = new Boolean[n];
            Arrays.fill(vis, false);
            // Initialize result
            int ans = 0;
            // Traverse array elements
            for (int i = 0; i < n; i++)
            {
                // already swapped and corrected or
                // already present at correct pos
                if (vis[i] || arrpos.get(i).getValue() == i)
                    continue;
                // find out the number of  node in
                // this cycle and add in ans
                int cycle_size = 0;
                int j = i;
                while (!vis[j])
                {
                    vis[j] = true;
                    // move to next node
                    j = arrpos.get(j).getValue();
                    cycle_size++;
                }
                // Update answer by adding current cycle.
                ans += (cycle_size - 1);
            }
            // Return result
            return ans;
        }
    https://www.includehelp.com/java-programs/minimum-swaps-required-to-sort-an-array.aspx
     static int minimumSwaps(int[] arr) {
      int swap=0;
      boolean visited[]=new boolean[arr.length];
    
      for(int i=0;i<arr.length;i++){
       int j=i,cycle=0;
    
       while(!visited[j]){
        visited[j]=true;
        j=arr[j]-1;
        cycle++;
       }
       
       if(cycle!=0)
        swap+=cycle-1;
      }
      return swap;
     }
    

    Find the Elements that are already sorted and focus on the rest of the elements for swapping.
    public static int minimumSwap (int[] inputarray)
     
    {
     
        int[] sorted = new int[inputarray.length];//take new array of size of the input array
     
       for (int i = 0; i < array.length; i++)
       {
     
         sorted[i] = inputarray[i];
     
       }//copy the input array into sorted array using for loop
     
       int n = sizeof(arr)/sizeof(arr[0]);
     
       //now sort the inputarray using below method.
     
       inputarray.sort(inputarray,inputarray+n);
     
       int j = 0;
     
       //now compare the sorted array with input array
     
       for (int i = 0; i < inputarray.length; i++)
       {
     
        if (inputarray[i] == sorted[j])
     
        j++;
      
       }
     
       //now we have count of not moved elements.Just subtract it from array lengths,
     
       will get the  minimum number of swaps required to sort.
     
       return array.length - j;
     
    }
    https://www.geeksforgeeks.org/minimum-number-of-swaps-required-to-sort-an-array-set-2/
    The idea is to create a vector of pair in C++ with first element as array values and second element as array indices. The next step is to sort the vector of pair according to the first element of the pair. After that traverse the vector and check if the index mapped with the value is correct or not, if not then keep swapping until the element is placed correctly and keep counting the number of swaps.
    int findMinSwap(int arr[] , int n)
    {
        // Declare a vector of pair     
        vector<pair<int,int>> vec(n);
          
        for(int i=0;i<n;i++)
        {
            vec[i].first=arr[i];
            vec[i].second=i;
        }
      
        // Sort the vector w.r.t the first
        // element of pair
        sort(vec.begin(),vec.end());
      
        int ans=0,c=0,j;
      
        for(int i=0;i<n;i++)
        {   
            // If the element is already placed
            // correct, then continue
            if(vec[i].second==i) 
                continue;
            else
            {
                // swap with its respective index 
                swap(vec[i].first,vec[vec[i].second].first);
                swap(vec[i].second,vec[vec[i].second].second); 
            
              
            // swap until the correct 
            // index matches
            if(i!=vec[i].second)
                --i;
              
            // each swap makes one element
            // move to its correct index, 
            // so increment answer
            ans++;
        }
      
        return ans;
    }
    X. http://geekyjumps.blogspot.com/2013/08/find-minimum-number-of-swap-required-to.html
    Given an array containing sequence of bits (0 or 1), you have to sort this array in the ascending order i.e. all 0' in first part of array followed by all 1's. The constraints is that you can swap only the adjacent elements in the array. Find the minimum number of swaps required to sort the given input array.

    Example: Given the array (0,0,1,0,1,0,1,1) the minimum number of swaps is 3.

    int swapRequired(int []array){
           //Boundary condition
           if(array == null || array.length == 0)
                 return 0;

           int swap = 0, count = 0;
            //iterate over all the elements of given array
           for(int i = array.length; i >= 0; i--){
                   if(array[i] == 0)
                        count++;            //count the number of 0s between two 1s
                   else
                        swap += count;
           }
           return swap;   //return the count of required swap
    }

    http://www.geeksforgeeks.org/minimum-swap-required-convert-binary-tree-binary-search-tree/
    Given the array representation of Complete Binary Tree i.e, if index i is the parent, index 2*i + 1 is the left child and index 2*i + 2 is the right child. The task is to find the minimum number of swap required to convert it into Binary Search Tree.
    The idea is to use the fact that inorder traversal of Binary Search Tree is in increasing order of their value.
    So, find the inorder traversal of the Binary Tree and store it in the array and try to sort the array. The minimum number of swap required to get the array sorted will be the answer. Please refer below post to find minimum number of swaps required to get the array sorted.
    Exercise: Can we extend this to normal binary tree, i.e., a binary tree represented using left and right pointers, and not necessarily complete?
    http://stackoverflow.com/questions/15152322/compute-the-minimal-number-of-swaps-to-order-a-sequence/15152602#15152602

    https://www.geeksforgeeks.org/number-swaps-sort-adjacent-swapping-allowed/
    Given an array arr[] of non negative integers. We can perform a swap operation on any two adjacent elements in the array. Find the minimum number of swaps needed to sort the array in ascending order.
    Examples :
    Input  : arr[] = {3, 2, 1}
    Output : 3
    We need to do following swaps
    (3, 2), (3, 1) and (1, 2)
    
    Input  : arr[] = {1, 20, 6, 4, 5}
    Output : 5
    
    )
    There is an interesting solution to this problem. It can be solved using the fact that number of swaps needed is equal to number of inversions. So we basically need to count inversions in array.
    The fact can be established using below observations:
    1) A sorted array has no inversions.
    2) An adjacent swap can reduce one inversion. Doing x adjacent swaps can reduce x inversions in an array.
    Read full article from Minimum number of swaps required to sort an array - GeeksforGeeks

    Labels

    LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

    Popular Posts