Could someone help me understand where this time limited exceeding comes from? The context is that in this threeSum method, given an array, I'm trying to record all possible combinations of three numbers that add up to 0. The original question comes from : https://leetcode.com/problems/3sum/
public class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> retList = new ArrayList<List<Integer>>();
Arrays.sort(nums); // O(nlogn)
for (int i=0; i<nums.length-1; i++){
int pleft;
int pright;
if (i!=0){
pleft = i-1;
while((nums[pleft]==nums[i]) && (pleft-1 >=0)){
pleft--;
}
} else {
pleft = i;
}
if (i!=nums.length-2){
pright = i+1;
while((nums[pright]==nums[i]) && (pright+1 < nums.length-1)){
pright++;
}
} else {
pright = i;
}
int sum;
while (true){
sum = nums[pleft]+nums[pright]+nums[i];
if (sum==0){
List<Integer> temp = new ArrayList<Integer>();
temp.add(nums[pleft]);
temp.add(nums[pright]);
temp.add(nums[i]);
retList.add(temp);
if (pleft-1>=0) pleft--;
if (pright+1<nums.length-1) pright++;
} else if (sum>0){
if (pleft-1>=0) pleft--;
} else { // less than zero
if (pright+1<nums.length-1) pright++;
}
}
}
return retList;
}
}
You're not breaking out of your while(true) loop. That code will just run forever and you won't return a value. You need to add a break or change the while (true) to while (condition)
Related
LeetCode Q:https://leetcode.com/problems/find-all-anagrams-in-a-string/
I believe what I have done is perfectly fine. However, it's giving me a TLE error. What changes do I have to do in order to run this program?
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int[] fors=new int[26];
int[] forp=new int[26];
for(int i=0;i<p.length();i++){
forp[p.charAt(i)-'a']++;
}
int k=p.length();
int len=s.length();
int i=0;
int j=0;
ArrayList<Integer> list=new ArrayList<>();
if(s.length()<p.length()) return list;
while(j<len){
fors[s.charAt(j)-'a']++;
if(j-i+1<k)j++;
if(j-i+1==k){
if(areSame(fors,forp)){
list.add(j-k+1);
fors[s.charAt(i)-'a']--;
i++;
j++;
}
}
}
return list;
}
public boolean areSame(int[] countS, int[] countP){
for(int i=0;i<26;i++){
if(countS[i]!=countP[i]){
return false;
}
}
return true;
}
}
I see 2 issues with your code. First, regarding TLE, you have an infinite loop because you iterate j and i only if the windows are equal.
if(areSame(fors,forp)){
list.add(j-k+1);
fors[s.charAt(i)-'a']--;
i++;
j++;
}
You should iterate i regardless. Fixing this is as simple as moving the iteration out of the if case.
if(areSame(fors,forp)){
list.add(j- p.length() +1);
}
fors[s.charAt(i)-'a']--;
i++;
Notice that I also move out the S - counter so that you keep moving even if the areSame checker is false.
The second issue is how you iterate j. By incrementing j before the areSame check, you check the windows 1 size too early. You can fix this by moving the j iteration to the end :)
class Solution {
public List<Integer> findAnagrams(String s, String p) {
int[] fors=new int[26];
int[] forp=new int[26];
for(int i=0;i<p.length();i++){
forp[p.charAt(i)-'a']++;
}
int i=0;
int j=0;
ArrayList<Integer> list=new ArrayList<>();
if(s.length()<p.length()) return list;
while(j<s.length()){
fors[s.charAt(j)-'a']++;
if(j-i+1== p.length()){
if(areSame(fors,forp)){
list.add(j- p.length() +1);
}
fors[s.charAt(i)-'a']--;
i++;
}
j++;
}
return list;
}
public boolean areSame(int[] countS, int[] countP){
for(int i=0;i<26;i++){
if(countS[i]!=countP[i]){
return false;
}
}
return true;
}
}
I'm struggling with a really simple problem in java. I've implemented quicksort in java that works on arraylists and can take any value. The problem is that it works only for an arraylist lower than about 8000 size.
Can anyone tell me what's wrong with my program? I think it might be connected with recursion depth limit but i'm not sure (because sometimes it works for larger sizes and sometimes not). How can I improve my quicksort implementation so it will work for much larger size of Arraylist like 100000?
import java.util.ArrayList;
import java.util.Random;
public class QuickSort {
Random gener;
int temporary,genertype,NInts,flag;
ArrayList<Integer> mylist;
public QuickSort(int type,int ilosc){
gener = new Random();
mylist= new ArrayList<>();
this.genertype=type;
this.NInts=ilosc;
}
void generate(){
if(genertype==0){
for(int i=0;i<NInts;i++){
mylist.add(gener.nextInt(100000));
}
}else {
for(int i=0;i<NInts;i++){
mylist.add(NInts-i);
}
}
}
int count1(ArrayList<Integer> list,int counter1,int counter2){
while(list.get(0)<list.get(counter1)){
if(counter1==counter2){
flag=1;
return counter1;
}
counter1++;
}
flag=0;
return counter1;
}
int count2(ArrayList<Integer> list,int counter1,int counter2){
while(list.get(0)>list.get(counter2)){
if(counter1==counter2){
flag=1;
return counter2;
}
counter2--;
}
flag=0;
return counter2;
}
public ArrayList<Integer> sorting(ArrayList<Integer> list) {
ArrayList<Integer> left = new ArrayList<Integer>();
ArrayList<Integer> right = new ArrayList<Integer>();
int counter1,counter2;
if (list.size() == 1) {
return list;
}else {
counter1=1;
counter2=list.size()-1;
while(counter1!=counter2) {
counter1=count1(list,counter1,counter2);
if(flag==1)
break;
counter2=count2(list,counter1,counter2);
if(flag==1)
break;
temporary = list.get(counter1);
list.set(counter1, list.get(counter2));
list.set(counter2, temporary);
}
for (int i = 0; i < counter1; i++) {
left.add(list.get(i));
}
for (int i = counter1; i < list.size(); i++) {
right.add(list.get(i));
}
left = sorting(left);
right = sorting(right);
list=merge(left, right);
}
return list;
}
ArrayList<Integer> merge(ArrayList<Integer> left, ArrayList<Integer> right) {
if(left.get(0)>right.get(right.size()-1)){
right.addAll(left);
return right;
}
else{
left.addAll(right);
return left;
}
}
void printing(){
for(int k=0;k<NInts;k++){
System.out.print(" "+mylist.get(k));
}
}
public static void main(String[] args){
QuickSort instance = new QuickSort(1,1000);
instance.generate();
instance.mylist=instance.sorting(instance.mylist);
instance.printing();
}
}
Ps.If you see anything wrong in my code, let me know so I can improve it :)
There could be many reasons why your code could not run for large number of inputs. Mostly it could be because the Heap Size capacity specified for your application is overflown. This can be resolved by increasing Heap Size of your application (check out this stackoverflow link on how to increase the heap size of your application)
This is my code
public int Test(int[]n){
if(n.length!=0){
int smallest = n[0];
for(int i = 0; i<n.length ; i++){
if(smallest > n[i]){
smallest = n[i];
return smallest;
}else{
return 0;
}
}
}
How do I change this code so that it throws an exception instead of returning zero if the list is empty?
you can simply achieve your goal:
public int Test(int[] n) {
if (n.length != 0) {
int smallest = n[0];
for (int i = 0; i < n.length; i++) {
if (smallest > n[i]) {
smallest = n[i];
}
}
return smallest;
} else {
throw new RuntimeException("List is empty!");
}
}
You can modify the else block as follows :
if(n.length!=0){
int smallest = n[0];
for(int i = 0; i<n.length ; i++){
if(smallest > n[i]){
smallest = n[i];
return smallest; // you might want to change this as well as suggested by #saeid
} else {
throw new CustomException();
}
}
}
where CustomException can extend any exception that you might want to throw.
You can simply check for the empty list, and if it's empty simply throw an exception.
throw new Exception("Your message that you want to show whenever the list is empty").
or else
Create a custom exception class.
class ListIsEmptyException extends Exception{
//create constructors as per your need
}
Now if list is empty
throw new ListIsEmptyException();
The return statement can not be in inner "if block" since it returns if first comparison success.But it depends on your requirement where you have to return the method. Try this code
create a custom exception
public class customException{
public customException(String msg) {
super(msg);
}
}
if(n.length!=0){
int smallest = n[0];
for(int i = 0; i<n.length ; i++){
if(smallest > n[i]){
smallest = n[i];
return smallest;
}else{
throw new customException("Its an empty list!!!");
}
}
Consider a List which have 60 or more elements. I want to break it into 6 List and add those to List. I am doing that because i want to send data to jsp in tabular format. Anyway, i am doing that but wanted to know if the way in which i am doing is good or not, cause i believe something better exist. Below is my code.
List<String> rollsAll = // from db
List<List<String>> rolls = new ArrayList<List<String>>();
int i=0;
for(String roll:rollsAll){
if(i<10)
{
if(i==0)
{
rolls.add(new ArrayList());
}
rolls.get(0).add(roll);
i++;
continue;
}
else if(i<20)
{
if(i==10)
{
rolls.add(new ArrayList());
}
rolls.get(1).add(roll);
i++;
continue;
}
else if(i<30)
{
if(i==20)
{
rolls.add(new ArrayList());
}
rolls.get(2).add(roll);
i++;
continue;
}else if(i<40)
{
if(i==30)
{
rolls.add(new ArrayList());
}
rolls.get(3).add(roll);
i++;
continue;
}else if(i<50)
{
if(i==40)
{
rolls.add(new ArrayList());
}
rolls.get(4).add(roll);
i++;
continue;
}else if(i<60)
{
if(i==50)
{
rolls.add(new ArrayList());
}
rolls.get(5).add(roll);
i++;
continue;
}else if(i<70)
{
if(i==60)
{
rolls.add(new ArrayList());
}
rolls.get(6).add(roll);
i++;
continue;
}else if(i<80)
{
if(i==70)
{
rolls.add(new ArrayList());
}
rolls.get(7).add(roll);
i++;
continue;
}else if(i<90)
{
if(i==80)
{
rolls.add(new ArrayList());
}
rolls.get(8).add(roll);
i++;
continue;
}else if(i<100)
{
if(i==90)
{
rolls.add(new ArrayList());
}
rolls.get(9).add(roll);
i++;
continue;
}else if(i<110)
{
if(i==100)
{
rolls.add(new ArrayList());
}
rolls.get(10).add(roll);
i++;
continue;
}else if(i<120)
{
if(i==110)
{
rolls.add(new ArrayList());
}
rolls.get(11).add(roll);
i++;
continue;
}
}
Thanks and Regards
Just walk the list 10 items at a time and use List.subList to grab the chunk that you need.
The below code does this and defensively copies the sub list.
int nPerSublist = 10;
List<String> rollsAll = // from db
List<List<String>> rolls = new ArrayList<List<String>>(
(rollsAll.size() + nPerSublist - 1) / nPerSublist);
for (int i = 0, n = rollsAll.size(); i < n; i += nPerSublist) {
rolls.add(new ArrayList<String>(rollsAll.subList(i, Math.min(i + nPerSublist, n))));
}
Using List.subList will produce an elegant way to achieve what you want:
Suppose I got a List of 1000 numbers and I want to split them into groups of 70:
List<Integer> numbers = new ArrayList<Integer>();
for (int i = 1; i <= 1000; i++) {
numbers.add(Integer.valueOf(i));
}
int totalItems = numbers.size();
int itemPerGroup = 70;
int totalGroup = (totalItems / itemPerGroup) + 1;
List<List<Integer>> groups = new ArrayList<List<Integer>>();
for (int groupCount = 1; groupCount <= totalGroup; groupCount++) {
int groupStartIndex = (groupCount - 1) * itemPerGroup;
int groupEndIndex = Math.min(numbers.size(), groupCount * itemPerGroup);
groups.add(numbers.subList(groupStartIndex, groupEndIndex));
}
I found this implementation on the web that you can use to store your data into a 2dArrayList, add this as a class to your project and you can use the methods there:
import java.util.ArrayList;
public class ArrayList2d<Type>
{
ArrayList<ArrayList<Type>> array;
public ArrayList2d()
{
array = new ArrayList<ArrayList<Type>>();
}
/**
* ensures a minimum capacity of num rows. Note that this does not guarantee
* that there are that many rows.
*
* #param num
*/
public void ensureCapacity(int num)
{
array.ensureCapacity(num);
}
/**
* Ensures that the given row has at least the given capacity. Note that
* this method will also ensure that getNumRows() >= row
*
* #param row
* #param num
*/
public void ensureCapacity(int row, int num)
{
ensureCapacity(row);
while (row < getNumRows())
{
array.add(new ArrayList<Type>());
}
array.get(row).ensureCapacity(num);
}
/**
* Adds an item at the end of the specified row. This will guarantee that at least row rows exist.
*/
public void Add(Type data, int row)
{
ensureCapacity(row);
while(row >= getNumRows())
{
array.add(new ArrayList<Type>());
}
array.get(row).add(data);
}
public Type get(int row, int col)
{
return array.get(row).get(col);
}
public void set(int row, int col, Type data)
{
array.get(row).set(col,data);
}
public void remove(int row, int col)
{
array.get(row).remove(col);
}
public boolean contains(Type data)
{
for (int i = 0; i < array.size(); i++)
{
if (array.get(i).contains(data))
{
return true;
}
}
return false;
}
public int getNumRows()
{
return array.size();
}
public int getNumCols(int row)
{
return array.get(row).size();
}
}
You can use that:
private static final int SIZE = 10; // size of an inner list
public List<List<String>> partition(final List<String> rolls)
{
final List<List<String>> ret = new ArrayList<List<String>>();
List<String> list;
int i = 0;
for (final String roll: rolls) {
if (i % SIZE == 0) {
list = new ArrayList<String>();
ret.add(list);
}
list.add(roll);
i++;
}
return ret;
}
Something like
List<String> rollsAll = // from db
List<List<String>> rolls = new ArrayList<List<String>>();
int size = rollsAll.size();
for (int i = 0; i < size / 10; i++) {
rolls.add(new ArrayList<String>(rollsAll.subList(10*i, 10*(i+1)));
}
// handle last part if size not divisible by 10
if (size % 10 > 0) {
rolls.add(new ArrayList<String>(rollsAll.subList(10 * (size / 10), size)));
}
List<List<String>> rolls = new ArrayList<List<String>>();
int i=0;
int currentArrayIndex = 0;
List<String> currentArray = null;
for(String roll:rollsAll){
if( (currentArrayIndex = i %10 ) ==0)
rolls.add(currentArray = new ArrayList());
currentArray.add(roll); i++;
}
Your approach is ok and other solutions are really good, but you're actually hardcoding the intervals to create the sublists. Instead, a simple counter and a elementsPerList variable could reduce your code to something more versatile:
public List<List<String>> splitList(List<String> original, int elementsPerList) {
List<List<String>> result = new ArrayList<List<String>>();
List<String> current = new ArrayList<String>();
result.add(current);
for(int i = 0; i < original.size(); i++) {
if(i < result.size() * elementsPerList) {
current.add(original.get(0));
} else {
current = new ArrayList<String>();
result.add(current);
current.add(original.get(0));
}
}
return result;
}
You just need to invoke this method with your current list and 10 as the amount of desired elements per list. Should you ever need to vary the amount of elements to split, you just need to pass the new amount to this method.
Use subList(fromIndex, toIndex)
List oldList = new LinkedList<String>();
// Add your elements in oldList
List newList1 = oldList.subList(0, 5);
List newList2 = oldList.subList(6, 10);
I am very new to programming and java so please don't laugh at this :). now..i looked over the net for the right implementation of the QuickSort algorithm and i am aware of that. but i tried to implement it myself in the very innocent,basic way i could think of. actually creating two seperate arrays(left,right) and continue to sort them and so on...
this is the code:
package excercise;
public class MyQuickSort {
public static int list[] = {6,5,3,1,8,7,2,4};
public static int[] addNumberToArray(int array[],int num){
int newArray[] = new int[array.length+1];
for(int i = 0;i<array.length;i++){
newArray[i] = array[i];
}
newArray[newArray.length-1] = num;
array = newArray;
return array;
}
public static int[] partition(int arr[]){
while(arr.length>1){
int pivotIndex = (int)(arr.length/2);
int left[] = new int[0];
int right[] = new int[0];
for(int i = 0;i<arr.length;i++){
if(i==pivotIndex){
continue;
}
else if(arr[i]<=arr[pivotIndex]){
left = addNumberToArray(left,arr[i]);
}
else{
right = addNumberToArray(right,arr[i]);
}
}
int origPivot = arr[pivotIndex];
int k = 0;
while(k<left.length){
arr[k] = left[k];
k++;
}
arr[k] = origPivot;
k++;
while(k<arr.length){
arr[k] = right[k-(left.length+1)];
}
if(left.length>1){
partition(left);
}
if(right.length>1){
partition(right);
}
}
return arr;
}
public static void main(String[]args){
list = partition(list);
for(int i = 0;i<list.length;i++){
System.out.print(list[i]+" ");
}
}
}
but why this is getting stick in a loop and don't work? i don't understand what is wrong with this code..except that this is not very efficient (to say the least)! but i am stubborn and want to try and make it work anyway..if you have any advices it will be great! thx in advance
ok,this is the new code,after debugging everything seems to work fine,but when i want to print the new sorted arr,it still prints me the original unsorted array. the recursion turn the whole thing back to where it starts. how can i make it "save the steps"? where should i put a "return" call and what should i return?
public class MyQuickSort {
public static int list[] = {6,5,3,1,8,7,2,4};
public static boolean sorted;
public static int[] addNumberToArray(int arr[],int num){
int newArr[] = new int[arr.length+1];
for(int i = 0;i<arr.length;i++){
newArr[i] = arr[i];
}
newArr[newArr.length-1] = num;
arr = newArr;
return arr;
}
public static void partition(int arr[]){
while(!sorted){
int pivotIndex = (int)(arr.length/2);
int left[] = new int[0];
int right[] = new int[0];
for(int i = 0;i<arr.length;i++){
if(i==pivotIndex){
continue;
}
else if(arr[i]<=arr[pivotIndex]){
left = addNumberToArray(left,arr[i]);
}
else{
right = addNumberToArray(right,arr[i]);
}
}
int origPivot = arr[pivotIndex];
int k = 0;
while(k<left.length){
arr[k] = left[k];
k++;
}
arr[k] = origPivot;
k++;
while(k<arr.length){
arr[k] = right[arr.length-arr.length-(left.length+1)+k];
k++;
}
if(left.length>1){
partition(left);
}
if(right.length>1){
partition(right);
}
if(left.length<=1&&right.length<=1){
sorted = true;
}
}
}
public static void main(String[] args) {
partition(list);
for(int i = 0;i<list.length;i++){
System.out.print(list[i]+" ");
}
}
}
your algorithm gets stuck in this loop
while(k<arr.length){
arr[k] = right[k-(left.length+1)];
}
the reason is that you don't increment your k.
try
while(k<arr.length){
arr[k] = right[k-(left.length+1)];
k++;
}
Cool! your implementation seem logically depicting quicksort. However, please note that quicksort is not to be implemented using additional buffers. It should be sorted in its own main array, recursing the call passing just the start and end bounds. Your implementation is more of a mergesort style, using quicksort logic. And yes, you missed the k++ as stated by the commenter above.