`
Everyday都不同
  • 浏览: 729301 次
  • 性别: Icon_minigender_1
  • 来自: 宇宙
社区版块
存档分类
最新评论

【Lintcode刷题】算法(持续更新)

阅读更多

Lintcode刷题地址:http://www.lintcode.com/zh-cn/problem/#_=_

一些大厂面试时喜欢考查的,对于锻炼自己的逻辑思维也大有裨益~

发现对链表的考察较多。。

 

0.经典的二分查找法(前提为有序序列)

/** 
     * 非递归二分查找 
     *  
     * @param num 
     * @param number 
     * @return 
     */  
    public static int binarySearch(int num[], int number) {  
        if (num == null || num.length == 0) {  
            return -1;  
        }  
        int start, end, mid;  
        start = 0;  
        end = num.length - 1;  
        while (start <= end) {  
            mid = (start + end) / 2;  
            if (num[mid] == number)  
                return mid;  
            else if (num[mid] > number) {  
                end = mid - 1;  
            } else {  
                start = mid + 1;  
            }  
        }  
        return -1;  
    }  
  
    /** 
     * 递归查找 
     *  
     * @param num 
     * @param number 
     * @return 
     */  
    public static int RecursivebinarySearch(int num[], int start, int end, int key) {  
        int mid = (start + end) / 2;  
        if (num == null || num.length == 0 || key < num[start] || key > num[end]) {  
            return -1;  
        } else if (num[mid] > key) {  
            return RecursivebinarySearch(num, start, mid - 1, key);  
        } else if (num[mid] < key) {  
            return RecursivebinarySearch(num, mid + 1, end, key);  
        } else {  
            return mid;  
        }  
  
    } 

 

 

1.二叉树的路径和:

 

class TreeNode {
     public int val;
     public TreeNode left, right;
     public TreeNode(int val) {
         this.val = val;
          this.left = this.right = null;
      }
 }



public class Solution {
    /*
     * @param root: the root of binary tree
     * @param target: An integer
     * @return: all valid paths
     */
    public List<List<Integer>> binaryTreePathSum(TreeNode root, int target) {
        // write your code here
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if(null == root) return result;
        Stack<Integer> stack = new Stack<Integer>();
        
        binaryTreePathSum(result, stack, root, 0, target);
        
        return result;
    }
    
    public void binaryTreePathSum(List<List<Integer>> result, Stack stack, TreeNode root, int sum, int target) {
        sum += root.val;
        stack.push(root.val);
        
        if(sum == target && root.left==null && root.right==null) {
            List<Integer> list = new ArrayList<Integer>(stack);
            result.add(list);
            stack.pop();
            return;
        }else{
            if(root.left != null) {
                binaryTreePathSum(result, stack, root.left, sum, target);
            }
            if(root.right != null) {
                binaryTreePathSum(result, stack, root.right, sum, target);
            }
            stack.pop();
        }
    }
}

 

 

2.合并排序数组
class Solution {
    /**
     * @param A and B: sorted integer array A and B.
     * @return: A new sorted integer array
     */
    public ArrayList<Integer> mergeSortedArray(ArrayList<Integer> A, ArrayList<Integer> B) {
        // write your code here
        int bSize = B.size();
        for(int i=0;i<bSize;i++)
            A.add(B.get(i));
        Collections.sort(A);
        return A;
    }
}

 不用Java API的做法(一般是考这个):

public int[] mergeSortedArr(int[] a, int[] b) {
  int[] result = new int[a.length + b.length];
  int i,j,k = 0;
  while(i<a.length && j<b.length) {//循环比较两个数最大长度的结果后,只会剩下一个数组的元素
    if(a[i] <= b[j]) {
      result[k++] = a[i++];
    }else {
      result[k++] = b[j++];
    }
  }

  while(i<a.length) {
    result[k++] = a[i++];
  }

  while(j<b.length) {
    result[k++] = b[j++];
  }

  return result;
}

 

 

3.翻转单链表

 

方式一:递归

 

public ListNode reverse1(ListNode head) {
        // 当为空或者本节点为末尾节点的时候
        if (head == null || head.next == null) //也是递归结束的条件
            return head;
        ListNode temp = head.next;
        ListNode reversedHead = reverse1(head.next);
        // 获取先前的下一个节点,让该节点指向自身
        temp.next = head;
        // 破坏以前自己指向下一个节点
        head.next = null;
        // 层层传递给最上面的
        return reversedHead;
    }

 方式二:非递归

 

 

public ListNode reverse(ListNode head){  
        ListNode p = head,q = null,front = null;  
        while(p!=null){  
            q = p.next;//设置q是p结点的后继结点,即用q来保持p的后继结点  
            p.next = front;//逆转,即使p.next指向p结点的前驱结点  
            front = p;//front向后移一步  
            p = q;//p向后移一步  
        }  
        head = front;//head指向原链表的最后一个结点,完成逆转  
        return head;
   }  

 

 

4.Replace With Greatest From Right

 

public class Solution {
    /*
     * @param : An array of integers.
     * @return: nothing
     */
    public void arrayReplaceWithGreatestFromRight(int[] nums) {
        // Write your code here.
        int size = nums.length;
        int max = nums[size - 1];
        nums[size - 1] = -1;
        
        for(int i=size-2; i>=0; i--) {
            int tmp = nums[i];
            nums[i] = max;
            if(tmp > max) {
                max = tmp;
            }
        }
    }
}

 

 

5.Sum of All Subsets

 

public class Solution {
    /*
     * @param : the given number
     * @return: Sum of elements in subsets
     */
    public int subSum(int n) {
        // write your code here
        if(n == 1) return 1;
        List<Integer> list = new ArrayList<>();
        for(int i=1; i<=n; i++) {
            list.add(i);
        }
        
       int subsetSum = getSubsetSum(list);
       return subsetSum;
    }
    
    public int getSubsetSum(List<Integer> list) {
        int sum = 0;
        List<List<Integer>> result = new ArrayList<>();
        for(int i=0; i<Math.pow(2, list.size()); i++) {
            List<Integer> subList = new ArrayList<>();
            int index = i;
            for(int j=0; j<list.size(); i++) {
                if((index & 1) == 1) {
                    subList.add(j);
                    sum += j;
                }
                index >>= 1;
            }
            if(subList.size() == 0) continue;
            result.add(subList);
        }
        return sum;
    }
}

 

 

6.连接两个字符串中的不同字符 

样例

给出 s1 = aacdb, s2 = gafd
返回 cbgf
给出 s1 = abcs, s2 = cxzca;
返回 bsxz

public static String concatenetedString(String s1, String s2) {
    // write your code here
    String str = "";
    
    List<Character> common = new ArrayList<>();
    char[] b = s1.toCharArray();
    for(int i=0; i<b.length; i++) {
        if(s2.indexOf(b[i]) > -1) {
            common.add(b[i]);
        }
    }
    
    List<Character> notin = new ArrayList<>();
    char[] b2 = s2.toCharArray();
    for(int i=0; i<b2.length; i++) {
        if(!common.contains(b2[i])) {
            notin.add(b2[i]);
        }
    }
    
    for(int i=0; i<b.length; i++) {
        if(!common.contains(b[i])) {
            str += b[i];
        }
    }
    
    for(int i=0; i<notin.size(); i++) {
        str += notin.get(i);
    }
    
    return str;
}

 

7.快慢指针查找中点
public class NodeListTest {
        
        public static void main(String[] args){  
        int[] array = {1,2,3,4,5,6,7};  
        Node node = NodeList.arrToNodeList(array);  

        NodeList.printNodeList(node);  
        System.out.println();
        System.out.println(NodeList.getMidNode(node));
    }  
  

}

//链表节点类
class Node {
        private Node next;//节点指向的下一个节点
        private int val;//本节点的值
        public Node getNext() {
                return next;
        }
        public void setNext(Node next) {
                this.next = next;
        }
        public int getVal() {
                return val;
        }
        public void setVal(int val) {
                this.val = val;
        }
        @Override
        public String toString() {
                return "Node [val=" + val + "]";
        }
        
}

//链表类
class NodeList { 
        private static Node head, tail, curr;
        
        /**
         * 将数组转换成链表,返回链表的头结点
         * @param arr
         * @return
         */
        public static Node arrToNodeList(int arr[]) {
                if(arr.length > 0) {
                        for(int i=0; i<arr.length; i++) {
                                curr = new Node();
                                //节点信息
                                curr.setNext(null);
                                curr.setVal(arr[i]);
                                if(head == null) {//对首节点的初始化赋值
                                        head = curr;
                                        tail = curr;
                                }else{//新的节点默认为尾节点
                                        tail.setNext(curr);
                                        tail = curr;
                                }
                        }
                }
                return head;
        }
        
        /**
         * 打印该链表的所有节点元素
         * @param head 头结点信息
         */
        public static void printNodeList(Node head) {
                System.out.print(head + ", ");
                while(head.getNext() != null) {
                        head = head.getNext();
                        System.out.print(head + ", ");
                }
        }
        
        /**
         * 根据链表信息(只包含头结点)取出中间节点的信息
         * @param head 头结点信息
         * @return
         */
        
        public static Node getMidNode(Node head) {
                //慢指针(每次走一步),快指针(每次走两步)初始状态都指向头结点
                Node stepOne=head, stepTwo = head;
                while(stepTwo!=null && stepTwo.getNext()!=null) {
                        stepTwo = stepTwo.getNext().getNext();
                        stepOne = stepOne.getNext();
                }
                return stepOne;
        }
}

 

8、判断一个链表是不是一个“环”

定义两个指针fast和slow,其中fast是快指针,slow是慢指针,二者的初始值都指向链表头,slow每前进一步,fast每次前进两步,两个指针同时向前移动,快指针每移动一次都要和慢指针比较,直到当快指针等于慢指针为止,就证明这个链表是带环的单向链表,否则,证明这个链表是不带环的循环链表(fast先行到达尾部为NULL,则为无环链表)。

public boolean isLoop(Node head){
        Node fast = head;
        Node slow = head;
        if (fast == null) {
            return false;
        }
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                return true;
            }
        }
        return !(fast == null || fast.next == null);
    }

 

 

9、查找有序序列中指定的数字第一次出现的位置

如“12345555678”查第一个“5”出现的位置(提示:二分查找法进行改进)

int myBinarySearch(int num[],int len,int key)  
{  
    int low=0;  
    int hight=len-1;  
    int mid=0;    
    int switchFind=0;  
    int index=0;      
    if (num[0]==key)  
        {  
            return 1;  
        }

    while (low<=hight)  
    {  
        mid=(hight+low)/2;  
        if (num[mid]==key)  
        {  
            switchFind=1;  
            break;  
        }  
        else if (num[mid]>key)  
        {  
            hight=mid-1;  
        }  
        else if (num[mid]<key)  
        {  
            low=mid+1;  
        }     
    }  
    while (switchFind)  
    {     
        mid--;  
          
        if (num[mid]!=key)  
        {  
            index=mid;  
            return index+2;  
        }  
    }  
    return -1;  
}  

 

10、写一个方法判断一个数是不是2的幂?

n & (n-1) == 0

附Java位运算:https://blog.csdn.net/lazyman_54/article/details/51283459

 

11、斐波那契数列递归实现与改进

是从0开始的:0,1,1,2,3,5……(不是从1开始)

public static int Recursion(int n){

        if(n==1){
            return 0;
        }

        if(n==2){
            return 1;
        }
        return Recursion(n-1)+Recursion(n-2);
    }

 时间复杂度:O(n^n)

改进:Recursion(n-1)已经包含了Recursion(n-2)的结果了,所以用递归的话又会把Recursion(n-2)展开,造成效率低下,

可以把每次加的结果给缓存起来,如下:

public static long  fil(int n){  
        long a=1;  
        long b=1;  
        long c=0;  
        if(n==1) return 1;  
        else if(n==2) return 1;  
        else if(n>2){  
            for (int i=3;i<=n;i++){  
                c=a+b;  
                a=b;  
                b=c;  
            }  
            return c;  
        }  
        else{  
            System.out.println("the number cannot be lower than zero");  
            return 0;  
        }     
    }

 

12、查找不重复的数字(其他数字都重复2遍)

对异或运算的巧妙运用(任何数异或00都得到这个数本身):

例如:

十进制:15  转成二进制为:11111111            

十进制:2   转成二进制为:00000010          

按位进行异或操作的结果为:11111101  ——>13  

如果我们将这个结果继续与其中的一个数进行异或运算,就可以得出另外一个数!  2^15^15 = 2    or     2^15^2 = 15

public static int NumberOf1(int[] arr) {  
        int len = arr.length;  
        int res = -1;  
        if(len > 1) {  
            res = arr[0];  
            for (int i = 1; i < len; i++) {  
                res = res ^ arr[i];  
            }  
        }  
        return res;  
    } 

 

13、字符串反转(用递归)

一般会想到用数组,String的charAt, toCharArray函数。

public static String strReverseWithArray(String string){
        if(string==null||string.length()==0)return string;
        int length = string.length();
        char [] array = string.toCharArray();
        for(int i = 0;i<length;i++){
            array[i] = string.charAt(length-1-i);
        }
        return new String(array);
    }

 

用递归的方式如下:

public static String strReverseWithRecursive(String string){
        if(string==null||string.length()==0)return string;
        int length = string.length();
        if(length==1){
            return string;
        }else{
            return  strReverseWithRecursive(string.substring(1))+string.charAt(0);
        }
    }

 

14、求n的加法组合,将一个整数拆分成多个整数相加的形式

例1:
3=1+1+1
3=1+2
3=3

解决思路:https://blog.csdn.net/bluetjs/article/details/52370916

public class Sum1ToN {  
  
    private void print(List<Integer> list) {  
        for (Integer k : list) {  
            System.out.print(k + "+");  
        }  
    }  
  
    private void f(int n, List<Integer> list, int start) {  
        if (n == 1) {  
            print(list);  
            System.out.println(1);  
        } else {  
            for (int i = start; i <=n / 2; i++) {  
                list.add(i);  
                f(n - i, list, i);  
                list.remove(list.size() -1);  
            }  
            print(list);  
            System.out.println(n);  
  
        }  
    }  
  
    public static void main(String[] args) {  
        List<Integer> list = new ArrayList<Integer>();  
        new Sum1ToN().f(9,list, 1);  
    }  
  
} 

 

0
0
分享到:
评论

相关推荐

    lintcode:lintcode刷题〜迟到总比不到好

    本资源名为“lintcode刷题〜迟到总比不到好”,暗示了即便延迟开始,持续学习和练习仍然是有益的。 标签为“Java”,意味着这个压缩包可能包含了用Java语言实现的Lintcode题目的解决方案。Java是一种广泛使用的面向...

    leetcode和杭电-Algorithm_exercises:算法练习

    持续更新中... 方便自己和他人浏览,作了一些整理,一些题中注释会有相应的说明 项目目录 HDU_OJ -- 杭电OJ上的部分题 Java刷题模板 -- 常见算法题及对应模板 LeetCode -- LeetCode上的一些习题,有对应题目序号 ...

    图像处理工程师+掌握的技能+所需看的书籍

    刷题网站如Lintcode可以帮助巩固编程基础和提高解决问题的能力。国防科大《大学计算机基础》MOOC课程则提供了计算机科学的基础理论。 数据结构与算法的理解至关重要,特别是对于图像处理中的搜索和优化问题。浙大的...

    20220607R4s9F6ZH.zip

    20220607R4s9F6ZH.zip

    【计算机求职笔试】资源

    【计算机求职笔试】资源

    基于S7-200 PLC与组态王的智能楼宇消防系统设计与实现

    内容概要:本文详细介绍了基于西门子S7-200 PLC和组态王软件构建的智能楼宇消防系统的设计与实现。首先阐述了硬件配置,包括烟雾传感器、手动报警按钮、排烟风机和声光报警器等设备的连接方式及其IO分配。接着深入解析了梯形图编程的关键逻辑,如输入滤波设置、分层报警策略以及带时间锁的控制流程。同时探讨了组态王监控画面的设计要点,特别是权限管理和报警弹窗的脚本实现。此外,还分享了一些常见的调试问题及解决方案,如电磁阀误动作、信号干扰等问题的处理方法。最终展示了系统的性能优势,强调了实时监测与快速响应的重要性。 适合人群:从事楼宇自动化、工业控制系统设计的技术人员,尤其是对PLC编程和SCADA系统有一定了解的工程师。 使用场景及目标:适用于新建或改造智能楼宇消防系统的项目规划与实施。目标是提高消防系统的响应速度和可靠性,确保在火灾发生时能够迅速采取措施,保障人员生命财产安全。 其他说明:文中提供了大量实际案例和经验教训,有助于读者更好地理解和应用相关技术和方法。

    2025姓名配对测算系统最新源码 带后台

    2025姓名配对测算系统最新源码 带后台 一套网上全新的UI,用于姓名配对,支持投流各大平台,全开源可进行二开! 投流的老板可以放心使用这套 后台登录地址:/admin    账号admin    密码admin123

    基于LabVIEW的多路压力数据采集系统设计与实现

    内容概要:本文详细介绍了基于LabVIEW构建的多路压力数据采集系统的硬件配置和软件架构。硬件方面,选择了合适的传感器(如STC的CYZ-102)和信号调理模块(如NI的SCXI-1520),确保系统的精度和稳定性。软件部分强调了DAQ助手的使用、生产者-消费者模式的应用以及TDMS格式的数据存储方法。此外,还分享了许多实用技巧,如差分输入应对电磁干扰、波形图控件优化、数据存储的块大小设置等。通过这些措施,系统实现了高效稳定的多通道压力数据采集,显著缩短了设备故障排查时间。 适合人群:从事工业自动化、数据采集系统设计的技术人员,尤其是有一定LabVIEW基础的研发人员。 使用场景及目标:适用于需要进行多通道压力监测的工业环境,如化工厂、液压测试台等。主要目标是提高数据采集的效率和准确性,减少设备故障排查时间,提升生产效率。 其他说明:文中提供了大量具体的配置代码和实践经验,帮助读者更好地理解和应用相关技术。同时,作者还分享了一些调试过程中遇到的问题及其解决方案,为后续开发提供宝贵的经验参考。

    S0073基于JavaSSM框架民宿管理系统1725784419.rar

    本资源为基于Java的SSM框架民宿管理系统的完整代码,适用于【计算机专业毕设/课设】。通过该项目,您可以快速实现民宿管理相关功能,并且该代码已进行了充分的注释和优化,便于开发者快速理解和二次开发。 资源特色: 功能齐全: 高效实现:代码经过优化,性能稳定, 详细注释:每个模块和函数均附带详细注释,便于理解和学习。帮助您快速上手和部署。 易于扩展:代码结构清晰,方便进行二次开发和功能拓展。 适用人群: 初学者:帮助您快速了解并实现[技术/功能]。 开发者:提供高效的代码实现,助力项目开发。 学术研究:为相关领域的研究人员提供有价值的代码资源。 下载说明: 本资源为付费资源,购买后可获得完整代码 支持提供技术支持,若有问题请及时联系我们。

    tbb-devel-2018.2-9.el8.x64-86.rpm.tar.gz

    1、文件说明: Centos8操作系统tbb-devel-2018.2-9.el8.rpm以及相关依赖,全打包为一个tar.gz压缩包 2、安装指令: #Step1、解压 tar -zxvf tbb-devel-2018.2-9.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm

    大学生智能消费记账系统的设计与实现.zip

    Java项目基于Springboot框架的课程设计,包含LW+ppt

    软考初级信息处理技术员上午试题模拟20及答案

    软考

    使用Matlab辅助设计开关电源.zip

    matlab

    西门子S7-200 SMART与施耐德ATV71变频器自动握手通讯方案及应用

    内容概要:本文详细介绍了如何通过西门子S7-200 SMART PLC与施耐德ATV71变频器建立稳定的自动握手通讯方案。主要内容涵盖硬件连接、参数设置、PLC编程实现DriveCom协议状态机、数据校验方法以及触摸屏配置等方面。文中特别强调了断电重启后的自动恢复机制,确保设备能够快速恢复正常运行,避免人工干预。同时,提供了具体的代码片段和注意事项,帮助读者理解和实施这一解决方案。 适合人群:从事工业自动化领域的工程师和技术人员,特别是那些负责变频器通讯和控制系统集成的专业人士。 使用场景及目标:适用于需要提高工业现场设备自动化水平的企业,旨在解决变频器断电重启后需要人工重新准备的问题,提升系统的稳定性和可靠性。 其他说明:本文不仅提供理论指导,还包括大量实战经验和具体案例分享,有助于读者更好地掌握相关技术和应对实际问题。

    在线考试系统.zip

    Java项目基于Springboot框架的课程设计,包含LW+ppt

    基于SUMO的交通仿真模型研究:信号控制、边界管理与车辆编队技术的应用

    内容概要:本文详细探讨了利用SUMO进行交通仿真的多个关键方面,包括但不限于信号控制、边界管理和车辆编队。首先介绍了通过TraCI接口实现的动态信号灯控制方法,能够根据实时交通状况调整绿灯时长,从而有效降低车辆延误率。其次讨论了高速公路的流量控制策略,如采用渐进式的流速控制和可变限速区来避免因事故造成的严重拥堵。此外,还展示了如何通过协同式自适应巡航控制系统(CACC)实现高效的车辆编队运行,确保车队内部的安全性和稳定性。文中提供了具体的Python代码示例以及XML配置片段,帮助读者更好地理解和实施相关技术。 适合人群:交通工程专业学生、研究人员和技术开发者,特别是对智能交通系统感兴趣的从业者。 使用场景及目标:适用于需要评估不同交通管理策略效果的研究机构或企业;旨在提高城市道路交通效率、减少交通事故发生频率并改善驾驶体验的技术创新项目。 其他说明:作者强调了交通控制参数非线性的特点,并指出在实践中应当灵活运用各种工具和技术手段不断优化仿真模型。同时提醒使用者注意细节之处(如相位编号从零开始),并且鼓励大家充分利用SUMO提供的可视化功能辅助调参工作。

    matlab实现全球定位系统GPS信号产生、捕获与追踪的深度研究-GPS-信号处理-伪随机码-三边测量-多路径效应修正-matlab

    内容概要:本文详细探讨了全球定位系统(GPS)的信号产生、捕获和追踪三个核心步骤,并通过Matlab源码实现相关算法。首先介绍了GPS信号产生的关键要素,包括伪随机码生成、数据编码和信号发射。接着讨论了信号捕获过程,涉及天线接收、码相位测量及其常用方法如滑动相关法。最后阐述了信号追踪的三边测量原理及误差修正措施,如电离层延迟补偿、地形效应补偿和多路径效应修正。通过具体Matlab代码示例展示了整个流程的实现,并附带了详细的运行步骤和结果分析。 适合人群:对GPS系统有兴趣的研究人员和技术爱好者,尤其是有一定编程基础并希望深入了解GPS内部机制的人群。 使用场景及目标:适用于学术研究、工程开发等领域,旨在帮助读者掌握GPS信号处理的基本理论和实践技能,提升定位精度和可靠性。 其他说明:文中提供的Matlab代码已在特定版本下测试通过,但不同版本可能存在差异。此外,还列举了一些参考文献供进一步学习。

    IT技术交流和分享平台的设计与实现.zip

    Java项目基于Springboot框架的课程设计,包含LW+ppt

    P2并联架构Cruise仿真模型与Simulink控制策略解析及应用

    内容概要:本文详细介绍了基于P2并联架构的Cruise仿真模型及其Simulink控制策略。首先,文章阐述了模型架构,特别是P2电机的位置选择以及行星齿轮组的参数配置,强调了扭矩耦合的优势。接着,深入探讨了控制策略,包括三层状态机嵌套的工况识别模块、滑动窗口方差计算用于预判驾驶意图、带遗忘因子的递推最小二乘法进行动态扭矩分配等关键技术。此外,文章还展示了速度跟随模块采用的带前馈的PID控制算法,并讨论了模型验证过程中遇到的问题及解决方案。最后,作者分享了一些有趣的彩蛋和隐藏功能,如秋名山模式和实时参数调整模块,以及模型的实际性能提升情况。 适合人群:从事汽车控制系统研究、混合动力汽车开发的技术人员,尤其是熟悉Matlab/Simulink平台的研发人员。 使用场景及目标:适用于希望深入了解P2并联架构Cruise仿真模型的设计原理和技术细节的研究者;旨在帮助开发者掌握先进的控制策略实现方法,提高仿真模型的精度和效率。 其他说明:文中提供了详细的代码片段和参数设置指南,便于读者理解和复现实验结果。同时,作者提醒读者注意一些潜在的技术陷阱,并给出了相应的解决建议。

Global site tag (gtag.js) - Google Analytics